feat(models): Add safe parsing for JSON deserialization

This commit is contained in:
cogwheel0
2025-12-09 22:35:07 +05:30
parent 0fc82d36f7
commit ed6d588518

View File

@@ -114,8 +114,9 @@ abstract class ChatCodeExecution with _$ChatCodeExecution {
@JsonKey(fromJson: _nullableString) String? name, @JsonKey(fromJson: _nullableString) String? name,
@JsonKey(fromJson: _nullableString) String? language, @JsonKey(fromJson: _nullableString) String? language,
@JsonKey(fromJson: _nullableString) String? code, @JsonKey(fromJson: _nullableString) String? code,
@JsonKey(fromJson: _safeCodeExecutionResult)
ChatCodeExecutionResult? result, ChatCodeExecutionResult? result,
Map<String, dynamic>? metadata, @JsonKey(fromJson: _safeJsonMap) Map<String, dynamic>? metadata,
}) = _ChatCodeExecution; }) = _ChatCodeExecution;
factory ChatCodeExecution.fromJson(Map<String, dynamic> json) => factory ChatCodeExecution.fromJson(Map<String, dynamic> json) =>
@@ -125,12 +126,12 @@ abstract class ChatCodeExecution with _$ChatCodeExecution {
@freezed @freezed
abstract class ChatCodeExecutionResult with _$ChatCodeExecutionResult { abstract class ChatCodeExecutionResult with _$ChatCodeExecutionResult {
const factory ChatCodeExecutionResult({ const factory ChatCodeExecutionResult({
String? output, @JsonKey(fromJson: _nullableString) String? output,
String? error, @JsonKey(fromJson: _nullableString) String? error,
@JsonKey(fromJson: _executionFilesFromJson, toJson: _executionFilesToJson) @JsonKey(fromJson: _executionFilesFromJson, toJson: _executionFilesToJson)
@Default(<ChatExecutionFile>[]) @Default(<ChatExecutionFile>[])
List<ChatExecutionFile> files, List<ChatExecutionFile> files,
Map<String, dynamic>? metadata, @JsonKey(fromJson: _safeJsonMap) Map<String, dynamic>? metadata,
}) = _ChatCodeExecutionResult; }) = _ChatCodeExecutionResult;
factory ChatCodeExecutionResult.fromJson(Map<String, dynamic> json) => factory ChatCodeExecutionResult.fromJson(Map<String, dynamic> json) =>
@@ -142,7 +143,7 @@ abstract class ChatExecutionFile with _$ChatExecutionFile {
const factory ChatExecutionFile({ const factory ChatExecutionFile({
@JsonKey(fromJson: _nullableString) String? name, @JsonKey(fromJson: _nullableString) String? name,
@JsonKey(fromJson: _nullableString) String? url, @JsonKey(fromJson: _nullableString) String? url,
Map<String, dynamic>? metadata, @JsonKey(fromJson: _safeJsonMap) Map<String, dynamic>? metadata,
}) = _ChatExecutionFile; }) = _ChatExecutionFile;
factory ChatExecutionFile.fromJson(Map<String, dynamic> json) => factory ChatExecutionFile.fromJson(Map<String, dynamic> json) =>
@@ -157,7 +158,7 @@ abstract class ChatSourceReference with _$ChatSourceReference {
@JsonKey(fromJson: _nullableString) String? url, @JsonKey(fromJson: _nullableString) String? url,
@JsonKey(fromJson: _nullableString) String? snippet, @JsonKey(fromJson: _nullableString) String? snippet,
@JsonKey(fromJson: _nullableString) String? type, @JsonKey(fromJson: _nullableString) String? type,
Map<String, dynamic>? metadata, @JsonKey(fromJson: _safeJsonMap) Map<String, dynamic>? metadata,
}) = _ChatSourceReference; }) = _ChatSourceReference;
factory ChatSourceReference.fromJson(Map<String, dynamic> json) => factory ChatSourceReference.fromJson(Map<String, dynamic> json) =>
@@ -324,3 +325,45 @@ String? _nullableString(dynamic value) {
final str = value.toString(); final str = value.toString();
return str.isEmpty ? null : str; return str.isEmpty ? null : str;
} }
/// Safely parse a `Map<String, dynamic>` from various formats.
/// Returns null if the value cannot be converted to a valid map or is empty.
Map<String, dynamic>? _safeJsonMap(dynamic value) {
if (value == null) return null;
if (value is Map<String, dynamic>) {
return value.isEmpty ? null : value;
}
if (value is Map) {
final result = <String, dynamic>{};
value.forEach((key, v) {
result[key.toString()] = v;
});
return result.isEmpty ? null : result;
}
return null;
}
/// Safely parse a ChatCodeExecutionResult from various formats.
/// Returns null if the value cannot be converted to a valid result.
ChatCodeExecutionResult? _safeCodeExecutionResult(dynamic value) {
if (value == null) return null;
if (value is Map<String, dynamic>) {
try {
return ChatCodeExecutionResult.fromJson(value);
} catch (_) {
return null;
}
}
if (value is Map) {
try {
final map = <String, dynamic>{};
value.forEach((key, v) {
map[key.toString()] = v;
});
return ChatCodeExecutionResult.fromJson(map);
} catch (_) {
return null;
}
}
return null;
}