@@ -50,6 +50,121 @@ describe("Command Validation", () => {
5050 parseCommand ( 'npm test | Select-String -NotMatch "node_modules" | Select-String "FAIL|Error"' ) ,
5151 ) . toEqual ( [ "npm test" , 'Select-String -NotMatch "node_modules"' , 'Select-String "FAIL|Error"' ] )
5252 } )
53+
54+ describe ( "newline handling" , ( ) => {
55+ it ( "splits commands by Unix newlines (\\n)" , ( ) => {
56+ expect ( parseCommand ( "echo hello\ngit status\nnpm install" ) ) . toEqual ( [
57+ "echo hello" ,
58+ "git status" ,
59+ "npm install" ,
60+ ] )
61+ } )
62+
63+ it ( "splits commands by Windows newlines (\\r\\n)" , ( ) => {
64+ expect ( parseCommand ( "echo hello\r\ngit status\r\nnpm install" ) ) . toEqual ( [
65+ "echo hello" ,
66+ "git status" ,
67+ "npm install" ,
68+ ] )
69+ } )
70+
71+ it ( "splits commands by old Mac newlines (\\r)" , ( ) => {
72+ expect ( parseCommand ( "echo hello\rgit status\rnpm install" ) ) . toEqual ( [
73+ "echo hello" ,
74+ "git status" ,
75+ "npm install" ,
76+ ] )
77+ } )
78+
79+ it ( "handles mixed line endings" , ( ) => {
80+ expect ( parseCommand ( "echo hello\ngit status\r\nnpm install\rls -la" ) ) . toEqual ( [
81+ "echo hello" ,
82+ "git status" ,
83+ "npm install" ,
84+ "ls -la" ,
85+ ] )
86+ } )
87+
88+ it ( "ignores empty lines" , ( ) => {
89+ expect ( parseCommand ( "echo hello\n\n\ngit status\r\n\r\nnpm install" ) ) . toEqual ( [
90+ "echo hello" ,
91+ "git status" ,
92+ "npm install" ,
93+ ] )
94+ } )
95+
96+ it ( "handles newlines with chain operators" , ( ) => {
97+ expect ( parseCommand ( 'npm install && npm test\ngit add .\ngit commit -m "test"' ) ) . toEqual ( [
98+ "npm install" ,
99+ "npm test" ,
100+ "git add ." ,
101+ 'git commit -m "test"' ,
102+ ] )
103+ } )
104+
105+ it ( "splits on actual newlines even within quotes" , ( ) => {
106+ // Note: Since we split by newlines first, actual newlines in the input
107+ // will split the command, even if they appear to be within quotes
108+ // Using template literal to create actual newline
109+ const commandWithNewlineInQuotes = `echo "Hello
110+ World"
111+ git status`
112+ // The quotes get stripped because they're no longer properly paired after splitting
113+ expect ( parseCommand ( commandWithNewlineInQuotes ) ) . toEqual ( [ "echo Hello" , "World" , "git status" ] )
114+ } )
115+
116+ it ( "handles quoted strings on single line" , ( ) => {
117+ // When quotes are on the same line, they are preserved
118+ expect ( parseCommand ( 'echo "Hello World"\ngit status' ) ) . toEqual ( [ 'echo "Hello World"' , "git status" ] )
119+ } )
120+
121+ it ( "handles complex multi-line commands" , ( ) => {
122+ const multiLineCommand = `npm install
123+ npm test && npm run build
124+ echo "Done" | tee output.log
125+ git status; git add .
126+ ls -la || echo "Failed"`
127+
128+ expect ( parseCommand ( multiLineCommand ) ) . toEqual ( [
129+ "npm install" ,
130+ "npm test" ,
131+ "npm run build" ,
132+ 'echo "Done"' ,
133+ "tee output.log" ,
134+ "git status" ,
135+ "git add ." ,
136+ "ls -la" ,
137+ 'echo "Failed"' ,
138+ ] )
139+ } )
140+
141+ it ( "handles newlines with subshells" , ( ) => {
142+ expect ( parseCommand ( "echo $(date)\nnpm test\ngit status" ) ) . toEqual ( [
143+ "echo" ,
144+ "date" ,
145+ "npm test" ,
146+ "git status" ,
147+ ] )
148+ } )
149+
150+ it ( "handles newlines with redirections" , ( ) => {
151+ expect ( parseCommand ( "npm test 2>&1\necho done\nls -la > files.txt" ) ) . toEqual ( [
152+ "npm test 2>&1" ,
153+ "echo done" ,
154+ "ls -la > files.txt" ,
155+ ] )
156+ } )
157+
158+ it ( "handles empty input with newlines" , ( ) => {
159+ expect ( parseCommand ( "\n\n\n" ) ) . toEqual ( [ ] )
160+ expect ( parseCommand ( "\r\n\r\n" ) ) . toEqual ( [ ] )
161+ expect ( parseCommand ( "\r\r\r" ) ) . toEqual ( [ ] )
162+ } )
163+
164+ it ( "handles whitespace-only lines" , ( ) => {
165+ expect ( parseCommand ( "echo hello\n \t \ngit status" ) ) . toEqual ( [ "echo hello" , "git status" ] )
166+ } )
167+ } )
53168 } )
54169
55170 describe ( "isAutoApprovedSingleCommand (legacy behavior)" , ( ) => {
0 commit comments