@@ -591,6 +591,26 @@ this.init();
591591 expect ( result . content ) . toBe ( 'function test() {\n return false;\n}\n' )
592592 }
593593 } )
594+
595+ it ( 'should strip line numbers with leading spaces' , ( ) => {
596+ const originalContent = 'function test() {\n return true;\n}\n'
597+ const diffContent = `test.ts
598+ <<<<<<< SEARCH
599+ 1 | function test() {
600+ 2 | return true;
601+ 3 | }
602+ =======
603+ 1 | function test() {
604+ 2 | return false;
605+ 3 | }
606+ >>>>>>> REPLACE`
607+
608+ const result = strategy . applyDiff ( originalContent , diffContent )
609+ expect ( result . success ) . toBe ( true )
610+ if ( result . success ) {
611+ expect ( result . content ) . toBe ( 'function test() {\n return false;\n}\n' )
612+ }
613+ } )
594614
595615 it ( 'should not strip when not all lines have numbers in either section' , ( ) => {
596616 const originalContent = 'function test() {\n return true;\n}\n'
@@ -711,6 +731,212 @@ this.init();
711731 } )
712732 } ) ;
713733
734+ describe ( 'insertion/deletion' , ( ) => {
735+ let strategy : SearchReplaceDiffStrategy
736+
737+ beforeEach ( ( ) => {
738+ strategy = new SearchReplaceDiffStrategy ( )
739+ } )
740+
741+ describe ( 'deletion' , ( ) => {
742+ it ( 'should delete code when replace block is empty' , ( ) => {
743+ const originalContent = `function test() {
744+ console.log("hello");
745+ // Comment to remove
746+ console.log("world");
747+ }`
748+ const diffContent = `test.ts
749+ <<<<<<< SEARCH
750+ // Comment to remove
751+ =======
752+ >>>>>>> REPLACE`
753+
754+ const result = strategy . applyDiff ( originalContent , diffContent )
755+ expect ( result . success ) . toBe ( true )
756+ if ( result . success ) {
757+ expect ( result . content ) . toBe ( `function test() {
758+ console.log("hello");
759+ console.log("world");
760+ }` )
761+ }
762+ } )
763+
764+ it ( 'should delete multiple lines when replace block is empty' , ( ) => {
765+ const originalContent = `class Example {
766+ constructor() {
767+ // Initialize
768+ this.value = 0;
769+ // Set defaults
770+ this.name = "";
771+ // End init
772+ }
773+ }`
774+ const diffContent = `test.ts
775+ <<<<<<< SEARCH
776+ // Initialize
777+ this.value = 0;
778+ // Set defaults
779+ this.name = "";
780+ // End init
781+ =======
782+ >>>>>>> REPLACE`
783+
784+ const result = strategy . applyDiff ( originalContent , diffContent )
785+ expect ( result . success ) . toBe ( true )
786+ if ( result . success ) {
787+ expect ( result . content ) . toBe ( `class Example {
788+ constructor() {
789+ }
790+ }` )
791+ }
792+ } )
793+
794+ it ( 'should preserve indentation when deleting nested code' , ( ) => {
795+ const originalContent = `function outer() {
796+ if (true) {
797+ // Remove this
798+ console.log("test");
799+ // And this
800+ }
801+ return true;
802+ }`
803+ const diffContent = `test.ts
804+ <<<<<<< SEARCH
805+ // Remove this
806+ console.log("test");
807+ // And this
808+ =======
809+ >>>>>>> REPLACE`
810+
811+ const result = strategy . applyDiff ( originalContent , diffContent )
812+ expect ( result . success ) . toBe ( true )
813+ if ( result . success ) {
814+ expect ( result . content ) . toBe ( `function outer() {
815+ if (true) {
816+ }
817+ return true;
818+ }` )
819+ }
820+ } )
821+ } )
822+
823+ describe ( 'insertion' , ( ) => {
824+ it ( 'should insert code at specified line when search block is empty' , ( ) => {
825+ const originalContent = `function test() {
826+ const x = 1;
827+ return x;
828+ }`
829+ const diffContent = `test.ts
830+ <<<<<<< SEARCH
831+ =======
832+ console.log("Adding log");
833+ >>>>>>> REPLACE`
834+
835+ const result = strategy . applyDiff ( originalContent , diffContent , 2 , 2 )
836+ expect ( result . success ) . toBe ( true )
837+ if ( result . success ) {
838+ expect ( result . content ) . toBe ( `function test() {
839+ console.log("Adding log");
840+ const x = 1;
841+ return x;
842+ }` )
843+ }
844+ } )
845+
846+ it ( 'should preserve indentation when inserting at nested location' , ( ) => {
847+ const originalContent = `function test() {
848+ if (true) {
849+ const x = 1;
850+ }
851+ }`
852+ const diffContent = `test.ts
853+ <<<<<<< SEARCH
854+ =======
855+ console.log("Before");
856+ console.log("After");
857+ >>>>>>> REPLACE`
858+
859+ const result = strategy . applyDiff ( originalContent , diffContent , 3 , 3 )
860+ expect ( result . success ) . toBe ( true )
861+ if ( result . success ) {
862+ expect ( result . content ) . toBe ( `function test() {
863+ if (true) {
864+ console.log("Before");
865+ console.log("After");
866+ const x = 1;
867+ }
868+ }` )
869+ }
870+ } )
871+
872+ it ( 'should handle insertion at start of file' , ( ) => {
873+ const originalContent = `function test() {
874+ return true;
875+ }`
876+ const diffContent = `test.ts
877+ <<<<<<< SEARCH
878+ =======
879+ // Copyright 2024
880+ // License: MIT
881+
882+ >>>>>>> REPLACE`
883+
884+ const result = strategy . applyDiff ( originalContent , diffContent , 1 , 1 )
885+ expect ( result . success ) . toBe ( true )
886+ if ( result . success ) {
887+ expect ( result . content ) . toBe ( `// Copyright 2024
888+ // License: MIT
889+
890+ function test() {
891+ return true;
892+ }` )
893+ }
894+ } )
895+
896+ it ( 'should handle insertion at end of file' , ( ) => {
897+ const originalContent = `function test() {
898+ return true;
899+ }`
900+ const diffContent = `test.ts
901+ <<<<<<< SEARCH
902+ =======
903+
904+ // End of file
905+ >>>>>>> REPLACE`
906+
907+ const result = strategy . applyDiff ( originalContent , diffContent , 4 , 4 )
908+ expect ( result . success ) . toBe ( true )
909+ if ( result . success ) {
910+ expect ( result . content ) . toBe ( `function test() {
911+ return true;
912+ }
913+
914+ // End of file` )
915+ }
916+ } )
917+
918+ it ( 'should insert at the start of the file if no start_line is provided for insertion' , ( ) => {
919+ const originalContent = `function test() {
920+ return true;
921+ }`
922+ const diffContent = `test.ts
923+ <<<<<<< SEARCH
924+ =======
925+ console.log("test");
926+ >>>>>>> REPLACE`
927+
928+ const result = strategy . applyDiff ( originalContent , diffContent )
929+ expect ( result . success ) . toBe ( true )
930+ if ( result . success ) {
931+ expect ( result . content ) . toBe ( `console.log("test");
932+ function test() {
933+ return true;
934+ }` )
935+ }
936+ } )
937+ } )
938+ } )
939+
714940 describe ( 'fuzzy matching' , ( ) => {
715941 let strategy : SearchReplaceDiffStrategy
716942
@@ -1241,8 +1467,8 @@ function two() {
12411467
12421468 it ( 'should document start_line and end_line parameters' , ( ) => {
12431469 const description = strategy . getToolDescription ( '/test' )
1244- expect ( description ) . toContain ( 'start_line: (required) The line number where the search block starts.' )
1245- expect ( description ) . toContain ( 'end_line: (required) The line number where the search block ends.' )
1470+ expect ( description ) . toContain ( 'start_line: (required) The line number where the search block starts (inclusive) .' )
1471+ expect ( description ) . toContain ( 'end_line: (required) The line number where the search block ends (inclusive) .' )
12461472 } )
12471473 } )
12481474} )
0 commit comments