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