Browse Source

dynamite: support nullability in TypeResult

Signed-off-by: Nikolas Rimikis <rimikis.nikolas@gmail.com>
pull/194/head
Nikolas Rimikis 2 years ago
parent
commit
b7a350e6a7
No known key found for this signature in database
GPG Key ID: 85ED1DE9786A4FF2
  1. 108
      packages/dynamite/dynamite/lib/src/openapi_builder.dart
  2. 10
      packages/dynamite/dynamite/lib/src/type_result/base.dart
  3. 5
      packages/dynamite/dynamite/lib/src/type_result/enum.dart
  4. 5
      packages/dynamite/dynamite/lib/src/type_result/list.dart
  5. 5
      packages/dynamite/dynamite/lib/src/type_result/map.dart
  6. 5
      packages/dynamite/dynamite/lib/src/type_result/object.dart
  7. 5
      packages/dynamite/dynamite/lib/src/type_result/type_result.dart

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

@ -725,6 +725,7 @@ class OpenAPIBuilder implements Builder {
uppercaseFirstCharacter: true, uppercaseFirstCharacter: true,
), ),
parameter.schema!, parameter.schema!,
nullable: dartParameterNullable,
); );
state.resolvedTypeCombinations.add(result); state.resolvedTypeCombinations.add(result);
@ -765,12 +766,7 @@ class OpenAPIBuilder implements Builder {
..name = _toDartName(parameter.name) ..name = _toDartName(parameter.name)
..required = dartParameterRequired; ..required = dartParameterRequired;
if (parameter.schema != null) { if (parameter.schema != null) {
b.type = refer( b.type = refer(result.nullableName);
_makeNullable(
result.name,
dartParameterNullable,
),
);
} }
if (defaultValueCode != null) { if (defaultValueCode != null) {
b.defaultTo = Code(defaultValueCode); b.defaultTo = Code(defaultValueCode);
@ -827,21 +823,23 @@ class OpenAPIBuilder implements Builder {
code.write("headers['Content-Type'] = '$mimeType';"); code.write("headers['Content-Type'] = '$mimeType';");
final dartParameterNullable = _isDartParameterNullable(
operation.requestBody!.required,
mediaType.schema?.nullable,
mediaType.schema?.default_,
);
final result = resolveType( final result = resolveType(
spec, spec,
state, state,
_toDartName('$operationId-request-$mimeType', uppercaseFirstCharacter: true), _toDartName('$operationId-request-$mimeType', uppercaseFirstCharacter: true),
mediaType.schema!, mediaType.schema!,
nullable: dartParameterNullable,
); );
final parameterName = _toDartName(result.name.replaceFirst(prefix, '')); final parameterName = _toDartName(result.name.replaceFirst(prefix, ''));
switch (mimeType) { switch (mimeType) {
case 'application/json': case 'application/json':
case 'application/x-www-form-urlencoded': case 'application/x-www-form-urlencoded':
final dartParameterNullable = _isDartParameterNullable(
operation.requestBody!.required,
mediaType.schema?.nullable,
mediaType.schema?.default_,
);
final dartParameterRequired = _isDartParameterRequired( final dartParameterRequired = _isDartParameterRequired(
operation.requestBody!.required, operation.requestBody!.required,
mediaType.schema?.default_, mediaType.schema?.default_,
@ -850,7 +848,7 @@ class OpenAPIBuilder implements Builder {
Parameter( Parameter(
(final b) => b (final b) => b
..name = parameterName ..name = parameterName
..type = refer(_makeNullable(result.name, dartParameterNullable)) ..type = refer(result.nullableName)
..named = true ..named = true
..required = dartParameterRequired, ..required = dartParameterRequired,
), ),
@ -1159,8 +1157,6 @@ final _dartKeywords = [
bool _isNonAlphaNumericString(final String input) => !RegExp(r'^[a-zA-Z0-9]$').hasMatch(input); bool _isNonAlphaNumericString(final String input) => !RegExp(r'^[a-zA-Z0-9]$').hasMatch(input);
String _makeNullable(final String type, final bool nullable) => nullable && type != 'dynamic' ? '$type?' : 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;
bool _isDartParameterNullable( bool _isDartParameterNullable(
@ -1241,8 +1237,9 @@ TypeResult resolveObject(
final OpenAPI spec, final OpenAPI spec,
final State state, final State state,
final String identifier, final String identifier,
final Schema schema, final Schema schema, {
) { final bool nullable = false,
}) {
if (!state.resolvedTypes.contains('${state.prefix}$identifier')) { if (!state.resolvedTypes.contains('${state.prefix}$identifier')) {
state.resolvedTypes.add('${state.prefix}$identifier'); state.resolvedTypes.add('${state.prefix}$identifier');
state.registeredJsonObjects.add('${state.prefix}$identifier'); state.registeredJsonObjects.add('${state.prefix}$identifier');
@ -1310,20 +1307,16 @@ TypeResult resolveObject(
state, state,
'${identifier}_${_toDartName(propertyName, uppercaseFirstCharacter: true)}', '${identifier}_${_toDartName(propertyName, uppercaseFirstCharacter: true)}',
propertySchema, propertySchema,
nullable: _isDartParameterNullable(
schema.required?.contains(propertyName),
propertySchema.nullable,
propertySchema.default_,
),
); );
b b
..name = _toDartName(propertyName) ..name = _toDartName(propertyName)
..returns = refer( ..returns = refer(result.nullableName)
_makeNullable(
result.name,
_isDartParameterNullable(
schema.required?.contains(propertyName),
propertySchema.nullable,
propertySchema.default_,
),
),
)
..type = MethodType.getter ..type = MethodType.getter
..docs.addAll(_descriptionToDocs(propertySchema.description)); ..docs.addAll(_descriptionToDocs(propertySchema.description));
@ -1398,7 +1391,10 @@ TypeResult resolveObject(
), ),
); );
} }
return TypeResultObject('${state.prefix}$identifier'); return TypeResultObject(
'${state.prefix}$identifier',
nullable: nullable,
);
} }
TypeResult resolveType( TypeResult resolveType(
@ -1407,10 +1403,14 @@ TypeResult resolveType(
final String identifier, final String identifier,
final Schema schema, { final Schema schema, {
final bool ignoreEnum = false, final bool ignoreEnum = false,
final bool nullable = false,
}) { }) {
TypeResult? result; TypeResult? result;
if (schema.ref == null && schema.ofs == null && schema.type == null) { if (schema.ref == null && schema.ofs == null && schema.type == null) {
return TypeResultBase('JsonObject'); return TypeResultBase(
'JsonObject',
nullable: nullable,
);
} }
if (schema.ref != null) { if (schema.ref != null) {
final name = schema.ref!.split('/').last; final name = schema.ref!.split('/').last;
@ -1419,6 +1419,7 @@ TypeResult resolveType(
state, state,
name, name,
spec.components!.schemas![name]!, spec.components!.schemas![name]!,
nullable: nullable,
); );
} else if (schema.ofs != null) { } else if (schema.ofs != null) {
if (!state.resolvedTypes.contains('${state.prefix}$identifier')) { if (!state.resolvedTypes.contains('${state.prefix}$identifier')) {
@ -1430,6 +1431,7 @@ TypeResult resolveType(
state, state,
'$identifier${schema.ofs!.indexOf(s)}', '$identifier${schema.ofs!.indexOf(s)}',
s, s,
nullable: !(schema.allOf?.contains(s) ?? false),
), ),
) )
.toList(); .toList();
@ -1486,7 +1488,7 @@ TypeResult resolveType(
final s = schema.ofs![results.indexOf(result)]; final s = schema.ofs![results.indexOf(result)];
b b
..name = fields[result.name] ..name = fields[result.name]
..returns = refer(_makeNullable(result.name, !(schema.allOf?.contains(s) ?? false))) ..returns = refer(result.nullableName)
..type = MethodType.getter ..type = MethodType.getter
..docs.addAll(_descriptionToDocs(s.description)); ..docs.addAll(_descriptionToDocs(s.description));
}, },
@ -1673,7 +1675,10 @@ TypeResult resolveType(
]); ]);
} }
result = TypeResultObject('${state.prefix}$identifier'); result = TypeResultObject(
'${state.prefix}$identifier',
nullable: nullable,
);
} else if (schema.isContentString) { } else if (schema.isContentString) {
final subResult = resolveType( final subResult = resolveType(
spec, spec,
@ -1682,26 +1687,45 @@ TypeResult resolveType(
schema.contentSchema!, schema.contentSchema!,
); );
result = TypeResultObject('ContentString', generics: [subResult]); result = TypeResultObject(
'ContentString',
generics: [subResult],
nullable: nullable,
);
} else { } else {
switch (schema.type) { switch (schema.type) {
case 'boolean': case 'boolean':
result = TypeResultBase('bool'); result = TypeResultBase(
'bool',
nullable: nullable,
);
break; break;
case 'integer': case 'integer':
result = TypeResultBase('int'); result = TypeResultBase(
'int',
nullable: nullable,
);
break; break;
case 'number': case 'number':
result = TypeResultBase('num'); result = TypeResultBase(
'num',
nullable: nullable,
);
break; break;
case 'string': case 'string':
switch (schema.format) { switch (schema.format) {
case 'binary': case 'binary':
result = TypeResultBase('Uint8List'); result = TypeResultBase(
'Uint8List',
nullable: nullable,
);
break; break;
} }
result = TypeResultBase('String'); result = TypeResultBase(
'String',
nullable: nullable,
);
break; break;
case 'array': case 'array':
if (schema.items != null) { if (schema.items != null) {
@ -1714,11 +1738,13 @@ TypeResult resolveType(
result = TypeResultList( result = TypeResultList(
'BuiltList', 'BuiltList',
subResult, subResult,
nullable: nullable,
); );
} else { } else {
result = TypeResultList( result = TypeResultList(
'BuiltList', 'BuiltList',
TypeResultBase('JsonObject'), TypeResultBase('JsonObject'),
nullable: nullable,
); );
} }
break; break;
@ -1729,6 +1755,7 @@ TypeResult resolveType(
result = TypeResultMap( result = TypeResultMap(
'BuiltMap', 'BuiltMap',
TypeResultBase('JsonObject'), TypeResultBase('JsonObject'),
nullable: nullable,
); );
} else { } else {
final subResult = resolveType( final subResult = resolveType(
@ -1740,17 +1767,22 @@ TypeResult resolveType(
result = TypeResultMap( result = TypeResultMap(
'BuiltMap', 'BuiltMap',
subResult, subResult,
nullable: nullable,
); );
} }
break; break;
} }
result = TypeResultBase('JsonObject'); result = TypeResultBase(
'JsonObject',
nullable: nullable,
);
break; break;
} }
if (schema.properties!.isEmpty) { if (schema.properties!.isEmpty) {
result = TypeResultMap( result = TypeResultMap(
'BuiltMap', 'BuiltMap',
TypeResultBase('JsonObject'), TypeResultBase('JsonObject'),
nullable: nullable,
); );
break; break;
} }
@ -1760,6 +1792,7 @@ TypeResult resolveType(
state, state,
identifier, identifier,
schema, schema,
nullable: nullable,
); );
break; break;
} }
@ -1867,6 +1900,7 @@ TypeResult resolveType(
result = TypeResultEnum( result = TypeResultEnum(
'${state.prefix}$identifier', '${state.prefix}$identifier',
result, result,
nullable: nullable,
); );
} }

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

@ -1,7 +1,10 @@
part of '../../dynamite.dart'; part of '../../dynamite.dart';
class TypeResultBase extends TypeResult { class TypeResultBase extends TypeResult {
TypeResultBase(super.name); TypeResultBase(
super.name, {
super.nullable,
});
@override @override
String? get _builderFactory => null; String? get _builderFactory => null;
@ -20,9 +23,10 @@ class TypeResultBase extends TypeResult {
@override @override
String deserialize(final String object, {final bool toBuilder = false}) { String deserialize(final String object, {final bool toBuilder = false}) {
if (name == 'JsonObject') { if (name == 'JsonObject') {
return 'JsonObject($object)'; return 'JsonObject($object)${nullable ? '?' : ''}';
} }
return '($object as $name)';
return '($object as $name ${nullable ? '?' : ''})';
} }
@override @override

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

@ -3,8 +3,9 @@ part of '../../dynamite.dart';
class TypeResultEnum extends TypeResult { class TypeResultEnum extends TypeResult {
TypeResultEnum( TypeResultEnum(
super.name, super.name,
this.subType, this.subType, {
); super.nullable,
});
final TypeResult subType; final TypeResult subType;

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

@ -3,8 +3,9 @@ part of '../../dynamite.dart';
class TypeResultList extends TypeResult { class TypeResultList extends TypeResult {
TypeResultList( TypeResultList(
super.name, super.name,
final TypeResult subType, final TypeResult subType, {
) : super(generics: [subType]); super.nullable,
}) : super(generics: [subType]);
TypeResult get subType => generics.first; TypeResult get subType => generics.first;

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

@ -3,8 +3,9 @@ part of '../../dynamite.dart';
class TypeResultMap extends TypeResult { class TypeResultMap extends TypeResult {
TypeResultMap( TypeResultMap(
super.name, super.name,
final TypeResult subType, final TypeResult subType, {
) : super(generics: [TypeResultBase('String'), subType]); super.nullable,
}) : super(generics: [TypeResultBase('String'), subType]);
TypeResult get subType => generics[1]; TypeResult get subType => generics[1];

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

@ -6,6 +6,7 @@ class TypeResultObject extends TypeResult {
TypeResultObject( TypeResultObject(
super.className, { super.className, {
super.generics, super.generics,
super.nullable,
}) : assert( }) : assert(
className != 'JsonObject' && className != 'Object' && className != 'dynamic', className != 'JsonObject' && className != 'Object' && className != 'dynamic',
'Use TypeResultBase instead', 'Use TypeResultBase instead',
@ -47,10 +48,10 @@ class TypeResultObject extends TypeResult {
@override @override
String deserialize(final String object, {final bool toBuilder = false}) { String deserialize(final String object, {final bool toBuilder = false}) {
if (className == 'ContentString') { if (className == 'ContentString') {
return 'jsonSerializers.deserialize(messages, specifiedType: const $fullType)! as $name'; return 'jsonSerializers.deserialize(messages, specifiedType: const $fullType)! as $name${nullable ? '?' : ''}';
} }
return '$name.fromJson($object as Object)${toBuilder ? '.toBuilder()' : ''}'; return '$name.fromJson($object as Object${nullable ? '?' : ''})${nullable && toBuilder ? '?' : ''}${toBuilder ? '.toBuilder()' : ''}';
} }
@override @override

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

@ -4,11 +4,14 @@ abstract class TypeResult {
TypeResult( TypeResult(
this.className, { this.className, {
this.generics = const [], this.generics = const [],
this.nullable = false,
}) : assert(!className.contains('<'), 'Specifiy generics in the generics parameter.'), }) : assert(!className.contains('<'), 'Specifiy generics in the generics parameter.'),
assert(!className.contains('?'), 'Nullability should not be specified in the type.'); assert(!className.contains('?'), 'Nullability should not be specified in the type.');
final String className; final String className;
final List<TypeResult> generics; final List<TypeResult> generics;
final bool nullable;
String get name { String get name {
if (generics.isNotEmpty) { if (generics.isNotEmpty) {
final buffer = StringBuffer('$className<') final buffer = StringBuffer('$className<')
@ -54,4 +57,6 @@ abstract class TypeResult {
final bool onlyChildren = false, final bool onlyChildren = false,
final String? mimeType, final String? mimeType,
}); });
String get nullableName => nullable ? '$name?' : name;
} }

Loading…
Cancel
Save