11use serde:: Serialize ;
2- use serde_json:: json;
2+ use serde_json:: { json, Value } ;
33use unicode_width:: { UnicodeWidthChar , UnicodeWidthStr } ;
44
55const MAX_COL_WIDTH : usize = 256 ;
@@ -22,7 +22,7 @@ impl From<&str> for OutputFormat {
2222pub fn output_success < T : Serialize > ( result : T , format : OutputFormat , compact : bool ) {
2323 if matches ! ( format, OutputFormat :: Json ) {
2424 if compact {
25- println ! ( "{}" , json! ( { "ok" : true , " result" : result } ) ) ;
25+ println ! ( "{}" , compact_success_value ( result) ) ;
2626 } else {
2727 println ! (
2828 "{}" ,
@@ -34,6 +34,29 @@ pub fn output_success<T: Serialize>(result: T, format: OutputFormat, compact: bo
3434 }
3535}
3636
37+ fn compact_success_value < T : Serialize > ( result : T ) -> Value {
38+ let mut obj = match serde_json:: to_value ( result) . unwrap_or ( Value :: Null ) {
39+ Value :: Object ( obj) => obj,
40+ value => return json ! ( { "ok" : true , "result" : value } ) ,
41+ } ;
42+
43+ let Some ( profile) = obj. remove ( "profile" ) else {
44+ return json ! ( { "ok" : true , "result" : Value :: Object ( obj) } ) ;
45+ } ;
46+
47+ let result = if obj. len ( ) == 1 && obj. contains_key ( "result" ) {
48+ obj. remove ( "result" ) . unwrap_or ( Value :: Null )
49+ } else {
50+ Value :: Object ( obj)
51+ } ;
52+
53+ if profile. is_null ( ) {
54+ return json ! ( { "ok" : true , "result" : result } ) ;
55+ }
56+
57+ json ! ( { "status" : "ok" , "result" : result, "profile" : profile } )
58+ }
59+
3760#[ allow( dead_code) ]
3861pub fn output_error ( code : & str , message : & str , format : OutputFormat , compact : bool ) {
3962 if matches ! ( format, OutputFormat :: Json ) && compact {
@@ -978,6 +1001,82 @@ mod tests {
9781001 ) ;
9791002 }
9801003
1004+ #[ test]
1005+ fn test_compact_json_lifts_profile_next_to_result_for_list_payloads ( ) {
1006+ let value = json ! ( {
1007+ "result" : [
1008+ { "id" : "1" , "name" : "alpha" }
1009+ ] ,
1010+ "profile" : [
1011+ "line one"
1012+ ]
1013+ } ) ;
1014+
1015+ let rendered = compact_success_value ( value) ;
1016+
1017+ assert_eq ! (
1018+ rendered,
1019+ json!( {
1020+ "status" : "ok" ,
1021+ "result" : [
1022+ { "id" : "1" , "name" : "alpha" }
1023+ ] ,
1024+ "profile" : [
1025+ "line one"
1026+ ]
1027+ } )
1028+ ) ;
1029+ }
1030+
1031+ #[ test]
1032+ fn test_compact_json_lifts_profile_next_to_result_for_object_payloads ( ) {
1033+ let value = json ! ( {
1034+ "healthy" : true ,
1035+ "version" : "0.1.x" ,
1036+ "profile" : [
1037+ "line one"
1038+ ]
1039+ } ) ;
1040+
1041+ let rendered = compact_success_value ( value) ;
1042+
1043+ assert_eq ! (
1044+ rendered,
1045+ json!( {
1046+ "status" : "ok" ,
1047+ "result" : {
1048+ "healthy" : true ,
1049+ "version" : "0.1.x"
1050+ } ,
1051+ "profile" : [
1052+ "line one"
1053+ ]
1054+ } )
1055+ ) ;
1056+ }
1057+
1058+ #[ test]
1059+ fn test_compact_json_treats_null_profile_as_absent ( ) {
1060+ let value = json ! ( {
1061+ "result" : [
1062+ { "id" : "1" , "name" : "alpha" }
1063+ ] ,
1064+ "profile" : null
1065+ } ) ;
1066+
1067+ let rendered = compact_success_value ( value. clone ( ) ) ;
1068+
1069+ assert_eq ! (
1070+ rendered,
1071+ json!( {
1072+ "ok" : true ,
1073+ "result" : [
1074+ { "id" : "1" , "name" : "alpha" }
1075+ ]
1076+ } )
1077+ ) ;
1078+ }
1079+
9811080 #[ test]
9821081 fn test_profile_section_is_not_duplicated_for_plain_object_output ( ) {
9831082 let value = json ! ( {
0 commit comments