@@ -39,6 +39,84 @@ extension StructUtils on Struct {
39
39
}
40
40
}
41
41
42
+ extension UnwrapProtoMapUtils on Map <String , dynamic > {
43
+ /// Deeply unwraps a nested proto map structure by removing unnecessary proto wrappers and
44
+ /// converting all nested values to their primitive Dart types.
45
+ ///
46
+ /// Handles:
47
+ /// - Removes 'Kind' wrappers from proto Values
48
+ /// - Removes 'fields' wrappers from proto Structs
49
+ /// - Converts proto scalar types (String, Number, Bool, Null)
50
+ /// - Converts proto complex types (List, Struct)
51
+ /// - Preserves original structure minus wrappers
52
+ Map <String , dynamic > unwrap () {
53
+ final result = < String , dynamic > {};
54
+
55
+ // Core recursive function that processes each value in the structure
56
+ dynamic unwrapValue (dynamic value) {
57
+ // Handle maps - primary case for proto wrapper removal
58
+ if (value is Map ) {
59
+ final mapValue = Map <String , dynamic >.from (value);
60
+
61
+ // Two main wrapper types to handle:
62
+
63
+ // 1. Kind wrapper (from proto Value)
64
+ if (mapValue.containsKey ('Kind' )) {
65
+ final kindValue = mapValue['Kind' ];
66
+ if (kindValue is Map ) {
67
+ final kindMap = Map <String , dynamic >.from (kindValue);
68
+
69
+ // Scalar types are direct conversions - base cases
70
+ if (kindMap.containsKey ('StringValue' )) return kindMap['StringValue' ];
71
+ if (kindMap.containsKey ('NumberValue' )) return kindMap['NumberValue' ];
72
+ if (kindMap.containsKey ('BoolValue' )) return kindMap['BoolValue' ];
73
+ if (kindMap.containsKey ('NullValue' )) return null ;
74
+
75
+ // Complex types need recursive handling - can be a base case when empty
76
+ if (kindMap.containsKey ('ListValue' )) {
77
+ final listValue = kindMap['ListValue' ];
78
+ if (listValue is Map && listValue.containsKey ('values' )) {
79
+ return (listValue['values' ] as List ).map (unwrapValue).toList ();
80
+ }
81
+ return [];
82
+ }
83
+
84
+ if (kindMap.containsKey ('StructValue' )) {
85
+ final structValue = kindMap['StructValue' ];
86
+ if (structValue is Map && structValue.containsKey ('fields' )) {
87
+ return Map <String , dynamic >.from (structValue['fields' ]).unwrap ();
88
+ }
89
+ }
90
+ }
91
+ return value;
92
+ }
93
+
94
+ // 2. Fields wrapper (from proto Struct)
95
+ if (mapValue.containsKey ('fields' )) {
96
+ return Map <String , dynamic >.from (mapValue['fields' ]).unwrap ();
97
+ }
98
+
99
+ // Regular map - continue unwrapping all values
100
+ return mapValue.map ((key, val) => MapEntry (key, unwrapValue (val)));
101
+ }
102
+
103
+ // Handle lists - unwrap each element
104
+ if (value is List ) {
105
+ return value.map (unwrapValue).toList ();
106
+ }
107
+
108
+ return value; // base case: primitive value
109
+ }
110
+
111
+ // Process each top-level key-value pair
112
+ forEach ((key, value) {
113
+ result[key] = unwrapValue (value);
114
+ });
115
+
116
+ return result;
117
+ }
118
+ }
119
+
42
120
extension ListValueUtils <T > on List <T > {
43
121
Value toValue () {
44
122
final values = map ((e) {
0 commit comments