@@ -722,9 +722,7 @@ pub(crate) fn loro_json_schema_to_js_json_schema(
722722 Ok ( value. into ( ) )
723723}
724724
725- pub ( crate ) fn text_delta_to_js_value (
726- delta : Vec < TextDelta > ,
727- ) -> Result < JsValue , JsValue > {
725+ pub ( crate ) fn text_delta_to_js_value ( delta : Vec < TextDelta > ) -> Result < JsValue , JsValue > {
728726 let arr = Array :: new ( ) ;
729727 let mut iter = delta. into_iter ( ) ;
730728 let mut current = iter. next ( ) ;
@@ -734,26 +732,35 @@ pub(crate) fn text_delta_to_js_value(
734732
735733 // Try to merge with next items
736734 while let Some ( next) = next_item. take ( ) {
737- match ( & mut item, next) {
735+ match ( & mut item, next) {
738736 (
739- TextDelta :: Insert { insert : i1, attributes : a1 } ,
740- TextDelta :: Insert { insert : i2, attributes : a2 }
737+ TextDelta :: Insert {
738+ insert : i1,
739+ attributes : a1,
740+ } ,
741+ TextDelta :: Insert {
742+ insert : i2,
743+ attributes : a2,
744+ } ,
741745 ) if a1 == & a2 => {
742746 i1. push_str ( & i2) ;
743747 // next_item is consumed, try next
744748 next_item = iter. next ( ) ;
745749 }
746750 (
747- TextDelta :: Retain { retain : r1, attributes : a1 } ,
748- TextDelta :: Retain { retain : r2, attributes : a2 }
751+ TextDelta :: Retain {
752+ retain : r1,
753+ attributes : a1,
754+ } ,
755+ TextDelta :: Retain {
756+ retain : r2,
757+ attributes : a2,
758+ } ,
749759 ) if a1 == & a2 => {
750760 * r1 += r2;
751761 next_item = iter. next ( ) ;
752762 }
753- (
754- TextDelta :: Delete { delete : d1 } ,
755- TextDelta :: Delete { delete : d2 }
756- ) => {
763+ ( TextDelta :: Delete { delete : d1 } , TextDelta :: Delete { delete : d2 } ) => {
757764 * d1 += d2;
758765 next_item = iter. next ( ) ;
759766 }
@@ -762,7 +769,7 @@ pub(crate) fn text_delta_to_js_value(
762769 next_item = Some ( next) ;
763770 break ;
764771 }
765- }
772+ }
766773 }
767774
768775 // Convert merged item to JS
@@ -771,25 +778,13 @@ pub(crate) fn text_delta_to_js_value(
771778 TextDelta :: Insert { insert, attributes } => {
772779 Reflect :: set ( & obj, & "insert" . into ( ) , & insert. into ( ) ) ?;
773780 if let Some ( attributes) = attributes {
774- if !attributes. is_empty ( ) {
775- let attrs = Object :: new ( ) ;
776- for ( k, v) in attributes {
777- Reflect :: set ( & attrs, & k. into ( ) , & convert ( v) ?) ?;
778- }
779- Reflect :: set ( & obj, & "attributes" . into ( ) , & attrs) ?;
780- }
781+ set_style_attributes ( & obj, attributes) ?;
781782 }
782783 }
783784 TextDelta :: Retain { retain, attributes } => {
784785 Reflect :: set ( & obj, & "retain" . into ( ) , & retain. into ( ) ) ?;
785786 if let Some ( attributes) = attributes {
786- if !attributes. is_empty ( ) {
787- let attrs = Object :: new ( ) ;
788- for ( k, v) in attributes {
789- Reflect :: set ( & attrs, & k. into ( ) , & convert ( v) ?) ?;
790- }
791- Reflect :: set ( & obj, & "attributes" . into ( ) , & attrs) ?;
792- }
787+ set_style_attributes ( & obj, attributes) ?;
793788 }
794789 }
795790 TextDelta :: Delete { delete } => {
@@ -802,3 +797,27 @@ pub(crate) fn text_delta_to_js_value(
802797 }
803798 Ok ( arr. into ( ) )
804799}
800+
801+ fn set_style_attributes (
802+ obj : & Object ,
803+ attributes : FxHashMap < String , LoroValue > ,
804+ ) -> Result < ( ) , JsValue > {
805+ if !attributes. is_empty ( ) {
806+ let attrs = Object :: new ( ) ;
807+ let mut is_empty = true ;
808+ for ( k, v) in attributes {
809+ if v. is_null ( ) {
810+ // We should ignore attribute with null value, since it should be treated as deleted
811+ continue ;
812+ }
813+
814+ is_empty = false ;
815+ Reflect :: set ( & attrs, & k. into ( ) , & convert ( v) ?) ?;
816+ }
817+
818+ if !is_empty {
819+ Reflect :: set ( obj, & "attributes" . into ( ) , & attrs) ?;
820+ }
821+ }
822+ Ok ( ( ) )
823+ }
0 commit comments