Nikolas Rimikis
1 year ago
10 changed files with 1088 additions and 1047 deletions
@ -0,0 +1,313 @@ |
|||||||
|
import 'package:code_builder/code_builder.dart'; |
||||||
|
import 'package:dynamite/src/builder/resolve_type.dart'; |
||||||
|
import 'package:dynamite/src/builder/state.dart'; |
||||||
|
import 'package:dynamite/src/helpers/dart_helpers.dart'; |
||||||
|
import 'package:dynamite/src/helpers/dynamite.dart'; |
||||||
|
import 'package:dynamite/src/helpers/typeresult.dart'; |
||||||
|
import 'package:dynamite/src/models/open_api.dart'; |
||||||
|
import 'package:dynamite/src/models/schema.dart'; |
||||||
|
import 'package:dynamite/src/type_result/type_result.dart'; |
||||||
|
|
||||||
|
TypeResult resolveObject( |
||||||
|
final OpenAPI spec, |
||||||
|
final String variablePrefix, |
||||||
|
final State state, |
||||||
|
final String identifier, |
||||||
|
final Schema schema, { |
||||||
|
final bool nullable = false, |
||||||
|
final bool isHeader = false, |
||||||
|
}) { |
||||||
|
final result = TypeResultObject( |
||||||
|
'${state.classPrefix}$identifier', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
if (state.resolvedTypes.add(result)) { |
||||||
|
state.output.add( |
||||||
|
Class( |
||||||
|
(final b) { |
||||||
|
b |
||||||
|
..name = '${state.classPrefix}$identifier' |
||||||
|
..docs.addAll(schema.formattedDescription) |
||||||
|
..abstract = true |
||||||
|
..implements.add( |
||||||
|
refer( |
||||||
|
'Built<${state.classPrefix}$identifier, ${state.classPrefix}${identifier}Builder>', |
||||||
|
), |
||||||
|
) |
||||||
|
..constructors.addAll([ |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..factory = true |
||||||
|
..lambda = true |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'b' |
||||||
|
..type = refer('void Function(${state.classPrefix}${identifier}Builder)?'), |
||||||
|
), |
||||||
|
) |
||||||
|
..redirect = refer('_\$${state.classPrefix}$identifier'), |
||||||
|
), |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..name = '_' |
||||||
|
..constant = true, |
||||||
|
), |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..factory = true |
||||||
|
..name = 'fromJson' |
||||||
|
..lambda = true |
||||||
|
..requiredParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'json' |
||||||
|
..type = refer('Map<String, dynamic>'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = const Code('_jsonSerializers.deserializeWith(serializer, json)!'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..methods.addAll([ |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'toJson' |
||||||
|
..returns = refer('Map<String, dynamic>') |
||||||
|
..lambda = true |
||||||
|
..body = const Code('_jsonSerializers.serializeWith(serializer, this)! as Map<String, dynamic>'), |
||||||
|
), |
||||||
|
for (final property in schema.properties!.entries) ...[ |
||||||
|
Method( |
||||||
|
(final b) { |
||||||
|
final propertyName = property.key; |
||||||
|
final propertySchema = property.value; |
||||||
|
final result = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
'${identifier}_${toDartName(propertyName, uppercaseFirstCharacter: true)}', |
||||||
|
propertySchema, |
||||||
|
nullable: isDartParameterNullable( |
||||||
|
schema.required?.contains(propertyName), |
||||||
|
propertySchema, |
||||||
|
), |
||||||
|
); |
||||||
|
|
||||||
|
b |
||||||
|
..name = toDartName(propertyName) |
||||||
|
..returns = refer(result.nullableName) |
||||||
|
..type = MethodType.getter |
||||||
|
..docs.addAll(propertySchema.formattedDescription); |
||||||
|
|
||||||
|
if (toDartName(propertyName) != propertyName) { |
||||||
|
b.annotations.add( |
||||||
|
refer('BuiltValueField').call([], { |
||||||
|
'wireName': literalString(propertyName), |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
}, |
||||||
|
), |
||||||
|
], |
||||||
|
Method((final b) { |
||||||
|
b |
||||||
|
..name = 'serializer' |
||||||
|
..returns = refer('Serializer<${state.classPrefix}$identifier>') |
||||||
|
..lambda = true |
||||||
|
..static = true |
||||||
|
..body = Code( |
||||||
|
isHeader |
||||||
|
? '_\$${state.classPrefix}${identifier}Serializer()' |
||||||
|
: "_\$${toCamelCase('${state.classPrefix}$identifier')}Serializer", |
||||||
|
) |
||||||
|
..type = MethodType.getter; |
||||||
|
if (isHeader) { |
||||||
|
b.annotations.add(refer('BuiltValueSerializer').call([], {'custom': refer('true')})); |
||||||
|
} |
||||||
|
}), |
||||||
|
]); |
||||||
|
|
||||||
|
final defaults = <String>[]; |
||||||
|
for (final property in schema.properties!.entries) { |
||||||
|
final propertySchema = property.value; |
||||||
|
if (propertySchema.default_ != null) { |
||||||
|
final value = propertySchema.default_!.toString(); |
||||||
|
final result = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
propertySchema.type!, |
||||||
|
propertySchema, |
||||||
|
); |
||||||
|
defaults.add('..${toDartName(property.key)} = ${valueToEscapedValue(result, value)}'); |
||||||
|
} |
||||||
|
} |
||||||
|
if (defaults.isNotEmpty) { |
||||||
|
b.methods.add( |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = '_defaults' |
||||||
|
..returns = refer('void') |
||||||
|
..static = true |
||||||
|
..lambda = true |
||||||
|
..annotations.add( |
||||||
|
refer('BuiltValueHook').call( |
||||||
|
[], |
||||||
|
{ |
||||||
|
'initializeBuilder': refer('true'), |
||||||
|
}, |
||||||
|
), |
||||||
|
) |
||||||
|
..requiredParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'b' |
||||||
|
..type = refer('${state.classPrefix}${identifier}Builder'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = Code( |
||||||
|
<String?>[ |
||||||
|
'b', |
||||||
|
...defaults, |
||||||
|
].join(), |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
}, |
||||||
|
), |
||||||
|
); |
||||||
|
if (isHeader) { |
||||||
|
state.output.add( |
||||||
|
Class( |
||||||
|
(final b) => b |
||||||
|
..name = '_\$${state.classPrefix}${identifier}Serializer' |
||||||
|
..implements.add(refer('StructuredSerializer<${state.classPrefix}$identifier>')) |
||||||
|
..fields.addAll([ |
||||||
|
Field( |
||||||
|
(final b) => b |
||||||
|
..name = 'types' |
||||||
|
..modifier = FieldModifier.final$ |
||||||
|
..type = refer('Iterable<Type>') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..assignment = Code('const [${state.classPrefix}$identifier, _\$${state.classPrefix}$identifier]'), |
||||||
|
), |
||||||
|
Field( |
||||||
|
(final b) => b |
||||||
|
..name = 'wireName' |
||||||
|
..modifier = FieldModifier.final$ |
||||||
|
..type = refer('String') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..assignment = Code("r'${state.classPrefix}$identifier'"), |
||||||
|
), |
||||||
|
]) |
||||||
|
..methods.addAll([ |
||||||
|
Method((final b) { |
||||||
|
b |
||||||
|
..name = 'serialize' |
||||||
|
..returns = refer('Iterable<Object?>') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..requiredParameters.addAll([ |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializers' |
||||||
|
..type = refer('Serializers'), |
||||||
|
), |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'object' |
||||||
|
..type = refer('${state.classPrefix}$identifier'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'specifiedType' |
||||||
|
..type = refer('FullType') |
||||||
|
..named = true |
||||||
|
..defaultTo = const Code('FullType.unspecified'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = const Code('throw UnimplementedError();'); |
||||||
|
}), |
||||||
|
Method((final b) { |
||||||
|
b |
||||||
|
..name = 'deserialize' |
||||||
|
..returns = refer('${state.classPrefix}$identifier') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..requiredParameters.addAll([ |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializers' |
||||||
|
..type = refer('Serializers'), |
||||||
|
), |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'serialized' |
||||||
|
..type = refer('Iterable<Object?>'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'specifiedType' |
||||||
|
..type = refer('FullType') |
||||||
|
..named = true |
||||||
|
..defaultTo = const Code('FullType.unspecified'), |
||||||
|
), |
||||||
|
); |
||||||
|
List<Code> deserializeProperty(final MapEntry<String, Schema> property) { |
||||||
|
final propertyName = property.key; |
||||||
|
final propertySchema = property.value; |
||||||
|
final result = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
'${identifier}_${toDartName(propertyName, uppercaseFirstCharacter: true)}', |
||||||
|
propertySchema, |
||||||
|
nullable: isDartParameterNullable(schema.required?.contains(propertyName), propertySchema), |
||||||
|
); |
||||||
|
|
||||||
|
return [ |
||||||
|
Code("case '$propertyName':"), |
||||||
|
if (result.className != 'String') ...[ |
||||||
|
if (result is TypeResultBase || result is TypeResultEnum) ...[ |
||||||
|
Code( |
||||||
|
'result.${toDartName(propertyName)} = ${result.deserialize(result.decode('value!'))};', |
||||||
|
), |
||||||
|
] else ...[ |
||||||
|
Code( |
||||||
|
'result.${toDartName(propertyName)}.replace(${result.deserialize(result.decode('value!'))});', |
||||||
|
), |
||||||
|
], |
||||||
|
] else ...[ |
||||||
|
Code( |
||||||
|
'result.${toDartName(propertyName)} = value!;', |
||||||
|
), |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
b.body = Block.of([ |
||||||
|
Code('final result = new ${state.classPrefix}${identifier}Builder();'), |
||||||
|
const Code(''), |
||||||
|
const Code('final iterator = serialized.iterator;'), |
||||||
|
const Code('while (iterator.moveNext()) {'), |
||||||
|
const Code('final key = iterator.current! as String;'), |
||||||
|
const Code('iterator.moveNext();'), |
||||||
|
const Code('final value = iterator.current! as String;'), |
||||||
|
const Code('switch (key) {'), |
||||||
|
for (final property in schema.properties!.entries) ...deserializeProperty(property), |
||||||
|
const Code('}'), |
||||||
|
const Code('}'), |
||||||
|
const Code(''), |
||||||
|
const Code('return result.build();'), |
||||||
|
]); |
||||||
|
}), |
||||||
|
]), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
@ -0,0 +1,523 @@ |
|||||||
|
import 'package:code_builder/code_builder.dart'; |
||||||
|
import 'package:dynamite/src/builder/resolve_object.dart'; |
||||||
|
import 'package:dynamite/src/builder/state.dart'; |
||||||
|
import 'package:dynamite/src/helpers/dart_helpers.dart'; |
||||||
|
import 'package:dynamite/src/helpers/typeresult.dart'; |
||||||
|
import 'package:dynamite/src/models/open_api.dart'; |
||||||
|
import 'package:dynamite/src/models/schema.dart'; |
||||||
|
import 'package:dynamite/src/type_result/type_result.dart'; |
||||||
|
|
||||||
|
TypeResult resolveType( |
||||||
|
final OpenAPI spec, |
||||||
|
final String variablePrefix, |
||||||
|
final State state, |
||||||
|
final String identifier, |
||||||
|
final Schema schema, { |
||||||
|
final bool ignoreEnum = false, |
||||||
|
final bool nullable = false, |
||||||
|
}) { |
||||||
|
TypeResult? result; |
||||||
|
if (schema.ref == null && schema.ofs == null && schema.type == null) { |
||||||
|
return TypeResultBase( |
||||||
|
'JsonObject', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
if (schema.ref != null) { |
||||||
|
final name = schema.ref!.split('/').last; |
||||||
|
result = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
name, |
||||||
|
spec.components!.schemas![name]!, |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else if (schema.ofs != null) { |
||||||
|
result = TypeResultObject( |
||||||
|
'${state.classPrefix}$identifier', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
if (state.resolvedTypes.add(result)) { |
||||||
|
final results = schema.ofs! |
||||||
|
.map( |
||||||
|
(final s) => resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
'$identifier${schema.ofs!.indexOf(s)}', |
||||||
|
s, |
||||||
|
nullable: !(schema.allOf?.contains(s) ?? false), |
||||||
|
), |
||||||
|
) |
||||||
|
.toList(); |
||||||
|
|
||||||
|
final fields = <String, String>{}; |
||||||
|
for (final result in results) { |
||||||
|
final dartName = toDartName(result.name.replaceFirst(state.classPrefix, '')); |
||||||
|
fields[result.name] = toFieldName(dartName, result.name.replaceFirst(state.classPrefix, '')); |
||||||
|
} |
||||||
|
|
||||||
|
state.output.addAll([ |
||||||
|
Class( |
||||||
|
(final b) { |
||||||
|
b |
||||||
|
..name = '${state.classPrefix}$identifier' |
||||||
|
..abstract = true |
||||||
|
..implements.add( |
||||||
|
refer( |
||||||
|
'Built<${state.classPrefix}$identifier, ${state.classPrefix}${identifier}Builder>', |
||||||
|
), |
||||||
|
) |
||||||
|
..constructors.addAll([ |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..name = '_' |
||||||
|
..constant = true, |
||||||
|
), |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..factory = true |
||||||
|
..lambda = true |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'b' |
||||||
|
..type = refer('void Function(${state.classPrefix}${identifier}Builder)?'), |
||||||
|
), |
||||||
|
) |
||||||
|
..redirect = refer('_\$${state.classPrefix}$identifier'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..methods.addAll([ |
||||||
|
Method( |
||||||
|
(final b) { |
||||||
|
b |
||||||
|
..name = 'data' |
||||||
|
..returns = refer('JsonObject') |
||||||
|
..type = MethodType.getter; |
||||||
|
}, |
||||||
|
), |
||||||
|
for (final result in results) ...[ |
||||||
|
Method( |
||||||
|
(final b) { |
||||||
|
final s = schema.ofs![results.indexOf(result)]; |
||||||
|
b |
||||||
|
..name = fields[result.name] |
||||||
|
..returns = refer(result.nullableName) |
||||||
|
..type = MethodType.getter |
||||||
|
..docs.addAll(s.formattedDescription); |
||||||
|
}, |
||||||
|
), |
||||||
|
], |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..static = true |
||||||
|
..name = 'fromJson' |
||||||
|
..lambda = true |
||||||
|
..returns = refer('${state.classPrefix}$identifier') |
||||||
|
..requiredParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'json' |
||||||
|
..type = refer('Object'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = const Code('_jsonSerializers.deserializeWith(serializer, json)!'), |
||||||
|
), |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'toJson' |
||||||
|
..returns = refer('Map<String, dynamic>') |
||||||
|
..lambda = true |
||||||
|
..body = const Code('_jsonSerializers.serializeWith(serializer, this)! as Map<String, dynamic>'), |
||||||
|
), |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializer' |
||||||
|
..returns = refer('Serializer<${state.classPrefix}$identifier>') |
||||||
|
..lambda = true |
||||||
|
..static = true |
||||||
|
..annotations.add(refer('BuiltValueSerializer').call([], {'custom': refer('true')})) |
||||||
|
..body = Code('_\$${state.classPrefix}${identifier}Serializer()') |
||||||
|
..type = MethodType.getter, |
||||||
|
), |
||||||
|
]); |
||||||
|
}, |
||||||
|
), |
||||||
|
Class( |
||||||
|
(final b) => b |
||||||
|
..name = '_\$${state.classPrefix}${identifier}Serializer' |
||||||
|
..implements.add(refer('PrimitiveSerializer<${state.classPrefix}$identifier>')) |
||||||
|
..fields.addAll([ |
||||||
|
Field( |
||||||
|
(final b) => b |
||||||
|
..name = 'types' |
||||||
|
..modifier = FieldModifier.final$ |
||||||
|
..type = refer('Iterable<Type>') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..assignment = Code('const [${state.classPrefix}$identifier, _\$${state.classPrefix}$identifier]'), |
||||||
|
), |
||||||
|
Field( |
||||||
|
(final b) => b |
||||||
|
..name = 'wireName' |
||||||
|
..modifier = FieldModifier.final$ |
||||||
|
..type = refer('String') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..assignment = Code("r'${state.classPrefix}$identifier'"), |
||||||
|
), |
||||||
|
]) |
||||||
|
..methods.addAll([ |
||||||
|
Method((final b) { |
||||||
|
b |
||||||
|
..name = 'serialize' |
||||||
|
..returns = refer('Object') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..requiredParameters.addAll([ |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializers' |
||||||
|
..type = refer('Serializers'), |
||||||
|
), |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'object' |
||||||
|
..type = refer('${state.classPrefix}$identifier'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'specifiedType' |
||||||
|
..type = refer('FullType') |
||||||
|
..named = true |
||||||
|
..defaultTo = const Code('FullType.unspecified'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = const Code('return object.data.value;'); |
||||||
|
}), |
||||||
|
Method((final b) { |
||||||
|
b |
||||||
|
..name = 'deserialize' |
||||||
|
..returns = refer('${state.classPrefix}$identifier') |
||||||
|
..annotations.add(refer('override')) |
||||||
|
..requiredParameters.addAll([ |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializers' |
||||||
|
..type = refer('Serializers'), |
||||||
|
), |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'data' |
||||||
|
..type = refer('Object'), |
||||||
|
), |
||||||
|
]) |
||||||
|
..optionalParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'specifiedType' |
||||||
|
..type = refer('FullType') |
||||||
|
..named = true |
||||||
|
..defaultTo = const Code('FullType.unspecified'), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = Code( |
||||||
|
<String>[ |
||||||
|
'final result = new ${state.classPrefix}${identifier}Builder()', |
||||||
|
'..data = JsonObject(data);', |
||||||
|
if (schema.allOf != null) ...[ |
||||||
|
for (final result in results) ...[ |
||||||
|
if (result is TypeResultBase || result is TypeResultEnum) ...[ |
||||||
|
'result.${fields[result.name]!} = ${result.deserialize('data')};', |
||||||
|
] else ...[ |
||||||
|
'result.${fields[result.name]!}.replace(${result.deserialize('data')});', |
||||||
|
], |
||||||
|
], |
||||||
|
] else ...[ |
||||||
|
if (schema.discriminator != null) ...[ |
||||||
|
'if (data is! Iterable) {', |
||||||
|
r"throw StateError('Expected an Iterable but got ${data.runtimeType}');", |
||||||
|
'}', |
||||||
|
'', |
||||||
|
'String? discriminator;', |
||||||
|
'', |
||||||
|
'final iterator = data.iterator;', |
||||||
|
'while (iterator.moveNext()) {', |
||||||
|
'final key = iterator.current! as String;', |
||||||
|
'iterator.moveNext();', |
||||||
|
'final Object? value = iterator.current;', |
||||||
|
"if (key == '${schema.discriminator!.propertyName}') {", |
||||||
|
'discriminator = value! as String;', |
||||||
|
'break;', |
||||||
|
'}', |
||||||
|
'}', |
||||||
|
], |
||||||
|
for (final result in results) ...[ |
||||||
|
if (schema.discriminator != null) ...[ |
||||||
|
"if (discriminator == '${result.name.replaceFirst(state.classPrefix, '')}'", |
||||||
|
if (schema.discriminator!.mapping != null && schema.discriminator!.mapping!.isNotEmpty) ...[ |
||||||
|
for (final key in schema.discriminator!.mapping!.entries |
||||||
|
.where( |
||||||
|
(final entry) => |
||||||
|
entry.value.endsWith('/${result.name.replaceFirst(state.classPrefix, '')}'), |
||||||
|
) |
||||||
|
.map((final entry) => entry.key)) ...[ |
||||||
|
" || discriminator == '$key'", |
||||||
|
], |
||||||
|
') {', |
||||||
|
], |
||||||
|
], |
||||||
|
'try {', |
||||||
|
if (result is TypeResultBase || result is TypeResultEnum) ...[ |
||||||
|
'result._${fields[result.name]!} = ${result.deserialize('data')};', |
||||||
|
] else ...[ |
||||||
|
'result._${fields[result.name]!} = ${result.deserialize('data')}.toBuilder();', |
||||||
|
], |
||||||
|
'} catch (_) {', |
||||||
|
if (schema.discriminator != null) ...[ |
||||||
|
'rethrow;', |
||||||
|
], |
||||||
|
'}', |
||||||
|
if (schema.discriminator != null) ...[ |
||||||
|
'}', |
||||||
|
], |
||||||
|
], |
||||||
|
if (schema.oneOf != null) ...[ |
||||||
|
"assert([${fields.values.map((final e) => 'result._$e').join(',')}].where((final x) => x != null).length >= 1, 'Need oneOf for \${result._data}');", |
||||||
|
], |
||||||
|
if (schema.anyOf != null) ...[ |
||||||
|
"assert([${fields.values.map((final e) => 'result._$e').join(',')}].where((final x) => x != null).length >= 1, 'Need anyOf for \${result._data}');", |
||||||
|
], |
||||||
|
], |
||||||
|
'return result.build();', |
||||||
|
].join(), |
||||||
|
); |
||||||
|
}), |
||||||
|
]), |
||||||
|
), |
||||||
|
]); |
||||||
|
} |
||||||
|
} else if (schema.isContentString) { |
||||||
|
final subResult = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
identifier, |
||||||
|
schema.contentSchema!, |
||||||
|
); |
||||||
|
|
||||||
|
result = TypeResultObject( |
||||||
|
'ContentString', |
||||||
|
generics: [subResult], |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else { |
||||||
|
switch (schema.type) { |
||||||
|
case 'boolean': |
||||||
|
result = TypeResultBase( |
||||||
|
'bool', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
case 'integer': |
||||||
|
result = TypeResultBase( |
||||||
|
'int', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
case 'number': |
||||||
|
result = TypeResultBase( |
||||||
|
'num', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
case 'string': |
||||||
|
switch (schema.format) { |
||||||
|
case 'binary': |
||||||
|
result = TypeResultBase( |
||||||
|
'Uint8List', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
result = TypeResultBase( |
||||||
|
'String', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
case 'array': |
||||||
|
if (schema.items != null) { |
||||||
|
final subResult = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
identifier, |
||||||
|
schema.items!, |
||||||
|
); |
||||||
|
result = TypeResultList( |
||||||
|
'BuiltList', |
||||||
|
subResult, |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else { |
||||||
|
result = TypeResultList( |
||||||
|
'BuiltList', |
||||||
|
TypeResultBase('JsonObject'), |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
case 'object': |
||||||
|
if (schema.properties == null) { |
||||||
|
if (schema.additionalProperties == null) { |
||||||
|
result = TypeResultBase( |
||||||
|
'JsonObject', |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else if (schema.additionalProperties is EmptySchema) { |
||||||
|
result = TypeResultMap( |
||||||
|
'BuiltMap', |
||||||
|
TypeResultBase('JsonObject'), |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else { |
||||||
|
final subResult = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
identifier, |
||||||
|
schema.additionalProperties!, |
||||||
|
); |
||||||
|
result = TypeResultMap( |
||||||
|
'BuiltMap', |
||||||
|
subResult, |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
} else if (schema.properties!.isEmpty) { |
||||||
|
result = TypeResultMap( |
||||||
|
'BuiltMap', |
||||||
|
TypeResultBase('JsonObject'), |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} else { |
||||||
|
result = resolveObject( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
identifier, |
||||||
|
schema, |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (result != null) { |
||||||
|
if (!ignoreEnum && schema.enum_ != null) { |
||||||
|
if (state.resolvedTypes.add(TypeResultEnum('${state.classPrefix}$identifier', result))) { |
||||||
|
state.output.add( |
||||||
|
Class( |
||||||
|
(final b) => b |
||||||
|
..name = '${state.classPrefix}$identifier' |
||||||
|
..extend = refer('EnumClass') |
||||||
|
..constructors.add( |
||||||
|
Constructor( |
||||||
|
(final b) => b |
||||||
|
..name = '_' |
||||||
|
..constant = true |
||||||
|
..requiredParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'name' |
||||||
|
..toSuper = true, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
..fields.addAll( |
||||||
|
schema.enum_!.map( |
||||||
|
(final value) => Field( |
||||||
|
(final b) { |
||||||
|
final result = resolveType( |
||||||
|
spec, |
||||||
|
variablePrefix, |
||||||
|
state, |
||||||
|
'$identifier${toDartName(value.toString(), uppercaseFirstCharacter: true)}', |
||||||
|
schema, |
||||||
|
ignoreEnum: true, |
||||||
|
); |
||||||
|
b |
||||||
|
..name = toDartName(value.toString()) |
||||||
|
..static = true |
||||||
|
..modifier = FieldModifier.constant |
||||||
|
..type = refer('${state.classPrefix}$identifier') |
||||||
|
..assignment = Code( |
||||||
|
'_\$${toCamelCase('${state.classPrefix}$identifier')}${toDartName(value.toString(), uppercaseFirstCharacter: true)}', |
||||||
|
); |
||||||
|
|
||||||
|
if (toDartName(value.toString()) != value.toString()) { |
||||||
|
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. ' |
||||||
|
'Please remove the enum values on ${state.classPrefix}$identifier.', |
||||||
|
); |
||||||
|
} |
||||||
|
b.annotations.add( |
||||||
|
refer('BuiltValueEnumConst').call([], { |
||||||
|
'wireName': refer(valueToEscapedValue(result, value.toString())), |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
}, |
||||||
|
), |
||||||
|
), |
||||||
|
) |
||||||
|
..methods.addAll([ |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'values' |
||||||
|
..returns = refer('BuiltSet<${state.classPrefix}$identifier>') |
||||||
|
..lambda = true |
||||||
|
..static = true |
||||||
|
..body = Code('_\$${toCamelCase('${state.classPrefix}$identifier')}Values') |
||||||
|
..type = MethodType.getter, |
||||||
|
), |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'valueOf' |
||||||
|
..returns = refer('${state.classPrefix}$identifier') |
||||||
|
..lambda = true |
||||||
|
..static = true |
||||||
|
..requiredParameters.add( |
||||||
|
Parameter( |
||||||
|
(final b) => b |
||||||
|
..name = 'name' |
||||||
|
..type = refer(result!.name), |
||||||
|
), |
||||||
|
) |
||||||
|
..body = Code('_\$valueOf${state.classPrefix}$identifier(name)'), |
||||||
|
), |
||||||
|
Method( |
||||||
|
(final b) => b |
||||||
|
..name = 'serializer' |
||||||
|
..returns = refer('Serializer<${state.classPrefix}$identifier>') |
||||||
|
..lambda = true |
||||||
|
..static = true |
||||||
|
..body = Code("_\$${toCamelCase('${state.classPrefix}$identifier')}Serializer") |
||||||
|
..type = MethodType.getter, |
||||||
|
), |
||||||
|
]), |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
result = TypeResultEnum( |
||||||
|
'${state.classPrefix}$identifier', |
||||||
|
result, |
||||||
|
nullable: nullable, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
state.resolvedTypes.add(result); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
throw Exception('Can not convert OpenAPI type "${schema.toJson()}" to a Dart type'); |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
import 'package:dynamite/src/builder/state.dart'; |
||||||
|
|
||||||
|
List<String> buildSerializer(final State state) { |
||||||
|
if (state.resolvedTypes.isNotEmpty) { |
||||||
|
return [ |
||||||
|
'// coverage:ignore-start', |
||||||
|
'final Serializers _serializers = (Serializers().toBuilder()', |
||||||
|
...state.resolvedTypes.map((final type) => type.serializers).expand((final element) => element).toSet(), |
||||||
|
').build();', |
||||||
|
'', |
||||||
|
'Serializers get ${state.variablePrefix}Serializers => _serializers;', |
||||||
|
'', |
||||||
|
'final Serializers _jsonSerializers = (_serializers.toBuilder()..addPlugin(StandardJsonPlugin())..addPlugin(const ContentStringPlugin())).build();', |
||||||
|
'', |
||||||
|
'T deserialize${state.classPrefix}<T>(final Object data) => _serializers.deserialize(data, specifiedType: FullType(T))! as T;', |
||||||
|
'', |
||||||
|
'Object? serialize${state.classPrefix}<T>(final T data) => _serializers.serialize(data, specifiedType: FullType(T));', |
||||||
|
'// coverage:ignore-end', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
return []; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
import 'package:code_builder/code_builder.dart'; |
||||||
|
import 'package:dynamite/src/type_result/type_result.dart'; |
||||||
|
|
||||||
|
class State { |
||||||
|
State({ |
||||||
|
required this.classPrefix, |
||||||
|
required this.variablePrefix, |
||||||
|
}); |
||||||
|
|
||||||
|
final String classPrefix; |
||||||
|
final String variablePrefix; |
||||||
|
final output = <Spec>[]; |
||||||
|
final resolvedTypes = <TypeResult>{}; |
||||||
|
} |
@ -0,0 +1,107 @@ |
|||||||
|
String toDartName( |
||||||
|
final String name, { |
||||||
|
final bool uppercaseFirstCharacter = false, |
||||||
|
}) { |
||||||
|
var result = ''; |
||||||
|
var upperCase = uppercaseFirstCharacter; |
||||||
|
var firstCharacter = !uppercaseFirstCharacter; |
||||||
|
for (final char in name.split('')) { |
||||||
|
if (_isNonAlphaNumericString(char)) { |
||||||
|
upperCase = true; |
||||||
|
} else { |
||||||
|
result += firstCharacter ? char.toLowerCase() : (upperCase ? char.toUpperCase() : char); |
||||||
|
upperCase = false; |
||||||
|
firstCharacter = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (_dartKeywords.contains(result) || RegExp(r'^[0-9]+$', multiLine: true).hasMatch(result)) { |
||||||
|
return '\$$result'; |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
final _dartKeywords = [ |
||||||
|
'assert', |
||||||
|
'break', |
||||||
|
'case', |
||||||
|
'catch', |
||||||
|
'class', |
||||||
|
'const', |
||||||
|
'continue', |
||||||
|
'default', |
||||||
|
'do', |
||||||
|
'else', |
||||||
|
'enum', |
||||||
|
'extends', |
||||||
|
'false', |
||||||
|
'final', |
||||||
|
'finally', |
||||||
|
'for', |
||||||
|
'if', |
||||||
|
'in', |
||||||
|
'is', |
||||||
|
'new', |
||||||
|
'null', |
||||||
|
'rethrow', |
||||||
|
'return', |
||||||
|
'super', |
||||||
|
'switch', |
||||||
|
'this', |
||||||
|
'throw', |
||||||
|
'true', |
||||||
|
'try', |
||||||
|
'var', |
||||||
|
'void', |
||||||
|
'while', |
||||||
|
'with', |
||||||
|
'async', |
||||||
|
'hide', |
||||||
|
'on', |
||||||
|
'show', |
||||||
|
'sync', |
||||||
|
'abstract', |
||||||
|
'as', |
||||||
|
'covariant', |
||||||
|
'deferred', |
||||||
|
'dynamic', |
||||||
|
'export', |
||||||
|
'extension', |
||||||
|
'external', |
||||||
|
'factory', |
||||||
|
'function', |
||||||
|
'get', |
||||||
|
'implements', |
||||||
|
'import', |
||||||
|
'interface', |
||||||
|
'library', |
||||||
|
'mixin', |
||||||
|
'operator', |
||||||
|
'part', |
||||||
|
'set', |
||||||
|
'static', |
||||||
|
'typedef', |
||||||
|
]; |
||||||
|
|
||||||
|
bool _isNonAlphaNumericString(final String input) => !RegExp(r'^[a-zA-Z0-9]$').hasMatch(input); |
||||||
|
|
||||||
|
String toFieldName(final String dartName, final String type) => dartName == type ? '\$$dartName' : dartName; |
||||||
|
|
||||||
|
String toCamelCase(final String name) { |
||||||
|
var result = ''; |
||||||
|
var upperCase = false; |
||||||
|
var firstCharacter = true; |
||||||
|
for (final char in name.split('')) { |
||||||
|
if (char == '_') { |
||||||
|
upperCase = true; |
||||||
|
} else if (char == r'$') { |
||||||
|
result += r'$'; |
||||||
|
} else { |
||||||
|
result += firstCharacter ? char.toLowerCase() : (upperCase ? char.toUpperCase() : char); |
||||||
|
upperCase = false; |
||||||
|
firstCharacter = false; |
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
// ignore_for_file: avoid_positional_boolean_parameters |
||||||
|
|
||||||
|
import 'package:dynamite/src/helpers/dart_helpers.dart'; |
||||||
|
import 'package:dynamite/src/models/parameter.dart'; |
||||||
|
import 'package:dynamite/src/models/schema.dart'; |
||||||
|
|
||||||
|
String filterMethodName(final String operationId, final String tag) { |
||||||
|
final expandedTag = tag.split('/').toList(); |
||||||
|
final parts = operationId.split('-'); |
||||||
|
final output = <String>[]; |
||||||
|
for (var i = 0; i < parts.length; i++) { |
||||||
|
if (expandedTag.length <= i || expandedTag[i] != parts[i]) { |
||||||
|
output.add(parts[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
return output.join('-'); |
||||||
|
} |
||||||
|
|
||||||
|
String clientName(final String tag) => '${toDartName(tag, uppercaseFirstCharacter: true)}Client'; |
||||||
|
|
||||||
|
bool isDartParameterNullable( |
||||||
|
final bool? required, |
||||||
|
final Schema? schema, |
||||||
|
) => |
||||||
|
(!(required ?? false) && schema?.default_ == null) || (schema?.nullable ?? false); |
||||||
|
|
||||||
|
bool isRequired( |
||||||
|
final bool? required, |
||||||
|
final dynamic default_, |
||||||
|
) => |
||||||
|
(required ?? false) && default_ == null; |
||||||
|
|
||||||
|
int sortRequiredParameters(final Parameter a, final Parameter b) { |
||||||
|
if (a.isDartRequired != b.isDartRequired) { |
||||||
|
if (a.isDartRequired && !b.isDartRequired) { |
||||||
|
return -1; |
||||||
|
} else { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
import 'package:dynamite/src/helpers/dart_helpers.dart'; |
||||||
|
import 'package:dynamite/src/type_result/type_result.dart'; |
||||||
|
|
||||||
|
String valueToEscapedValue(final TypeResult result, final dynamic value) { |
||||||
|
if (result is TypeResultBase && result.name == 'String') { |
||||||
|
return "'$value'"; |
||||||
|
} |
||||||
|
if (result is TypeResultList) { |
||||||
|
return 'const $value'; |
||||||
|
} |
||||||
|
if (result is TypeResultEnum) { |
||||||
|
return '${result.name}.${toDartName(value.toString())}'; |
||||||
|
} |
||||||
|
return value.toString(); |
||||||
|
} |
Loading…
Reference in new issue