@@ -20,6 +20,142 @@ function hasHereDocument(command: string): boolean {
2020 return hereDocPattern . test ( command )
2121}
2222
23+ /**
24+ * Detects if a command contains a multiline string literal
25+ */
26+ function hasMultilineString ( command : string ) : boolean {
27+ // First check if the command has line continuations - these are NOT multiline strings
28+ // Line continuations end with backslash
29+ if ( / \\ \s * \n / . test ( command ) ) {
30+ return false
31+ }
32+
33+ // Check for multiline strings in quotes that span multiple lines
34+ // This is a simplified check - looks for quotes with newlines between them
35+ const lines = command . split ( "\n" )
36+ let inString = false
37+ let stringDelimiter = ""
38+ let escapeNext = false
39+
40+ for ( const line of lines ) {
41+ for ( let i = 0 ; i < line . length ; i ++ ) {
42+ const char = line [ i ]
43+
44+ if ( escapeNext ) {
45+ escapeNext = false
46+ continue
47+ }
48+
49+ if ( char === "\\" ) {
50+ escapeNext = true
51+ continue
52+ }
53+
54+ if ( ( char === '"' || char === "'" ) && ! inString ) {
55+ inString = true
56+ stringDelimiter = char
57+ } else if ( char === stringDelimiter && inString ) {
58+ inString = false
59+ stringDelimiter = ""
60+ }
61+ }
62+ // If we're still in a string after processing a line, it's multiline
63+ if ( inString && lines . indexOf ( line ) < lines . length - 1 ) {
64+ return true
65+ }
66+ }
67+
68+ return false
69+ }
70+
71+ /**
72+ * Converts multiline strings to single-line with escaped newlines
73+ */
74+ function convertMultilineStrings ( command : string ) : string {
75+ // Handle multiline strings by replacing newlines with \n
76+ const lines = command . split ( "\n" )
77+ const result : string [ ] = [ ]
78+ let inString = false
79+ let stringDelimiter = ""
80+ let currentString = ""
81+ let beforeString = "" // Track text before the string starts
82+ let escapeNext = false
83+
84+ for ( let lineIndex = 0 ; lineIndex < lines . length ; lineIndex ++ ) {
85+ const line = lines [ lineIndex ]
86+ let processedLine = ""
87+
88+ for ( let i = 0 ; i < line . length ; i ++ ) {
89+ const char = line [ i ]
90+
91+ if ( escapeNext ) {
92+ // We're escaping this character
93+ if ( inString ) {
94+ currentString += "\\" + char
95+ } else {
96+ processedLine += "\\" + char
97+ }
98+ escapeNext = false
99+ continue
100+ }
101+
102+ if ( char === "\\" ) {
103+ // This might be an escape character
104+ const nextChar = i < line . length - 1 ? line [ i + 1 ] : ""
105+ if ( nextChar === '"' || nextChar === "'" ) {
106+ // It's escaping a quote
107+ escapeNext = true
108+ continue
109+ } else {
110+ // It's just a backslash
111+ if ( inString ) {
112+ currentString += char
113+ } else {
114+ processedLine += char
115+ }
116+ }
117+ } else if ( ( char === '"' || char === "'" ) && ! inString ) {
118+ // Starting a string
119+ inString = true
120+ stringDelimiter = char
121+ beforeString = processedLine // Save text before string
122+ currentString = char
123+ processedLine = "" // Clear processed line as we're now in a string
124+ } else if ( char === stringDelimiter && inString ) {
125+ // Ending a string
126+ currentString += char
127+ processedLine = beforeString + currentString + processedLine
128+ inString = false
129+ stringDelimiter = ""
130+ currentString = ""
131+ beforeString = ""
132+ } else if ( inString ) {
133+ // Inside a string
134+ currentString += char
135+ } else {
136+ // Outside a string
137+ processedLine += char
138+ }
139+ }
140+
141+ if ( inString && lineIndex < lines . length - 1 ) {
142+ // We're in a multiline string, add \n for the newline
143+ currentString += "\\n"
144+ } else if ( ! inString && processedLine ) {
145+ // Not in a string, add the processed line
146+ result . push ( processedLine )
147+ }
148+ }
149+
150+ // If we're still in a string at the end, complete it
151+ if ( inString && currentString ) {
152+ // Close the unclosed string and add it with the text before it
153+ result . push ( beforeString + currentString )
154+ }
155+
156+ return result . join ( "\n" )
157+ }
158+
23159/**
24160 * Main function to convert multiline commands to single line
25161 * Uses a simple approach: join lines with semicolons for most cases
@@ -39,6 +175,24 @@ export function convertMultilineToSingleLine(command: string): ConversionResult
39175 }
40176 }
41177
178+ // Check if command contains multiline strings
179+ if ( hasMultilineString ( command ) ) {
180+ // Convert multiline strings to single-line with \n
181+ try {
182+ const converted = convertMultilineStrings ( command )
183+ // After converting strings, check if there are still multiple lines
184+ if ( ! converted . includes ( "\n" ) ) {
185+ return { success : true , command : converted }
186+ }
187+ // If there are still multiple lines after string conversion,
188+ // continue with normal processing
189+ command = converted
190+ } catch ( error ) {
191+ // If string conversion fails, continue with normal processing
192+ console . log ( `[multilineCommandConverter] String conversion failed: ${ error . message } ` )
193+ }
194+ }
195+
42196 try {
43197 // Simple approach: handle common patterns
44198 let result = command
0 commit comments