* Builds command parts from parsed entries, handling strings and operators. * Special handling for file descriptor redirections to preserve them as single units.
( parsed: ParseEntry[], start: number, end: number, )
| 117 | * Special handling for file descriptor redirections to preserve them as single units. |
| 118 | */ |
| 119 | function buildCommandParts( |
| 120 | parsed: ParseEntry[], |
| 121 | start: number, |
| 122 | end: number, |
| 123 | ): string[] { |
| 124 | const parts: string[] = [] |
| 125 | // Track if we've seen a non-env-var string token yet |
| 126 | // Environment variables are only valid at the start of a command |
| 127 | let seenNonEnvVar = false |
| 128 | |
| 129 | for (let i = start; i < end; i++) { |
| 130 | const entry = parsed[i] |
| 131 | |
| 132 | // Check for file descriptor redirections (e.g., 2>&1, 2>/dev/null) |
| 133 | if ( |
| 134 | typeof entry === 'string' && |
| 135 | /^[012]$/.test(entry) && |
| 136 | i + 2 < end && |
| 137 | isOperator(parsed[i + 1]) |
| 138 | ) { |
| 139 | const op = parsed[i + 1] as { op: string } |
| 140 | const target = parsed[i + 2] |
| 141 | |
| 142 | // Handle 2>&1 style redirections |
| 143 | if ( |
| 144 | op.op === '>&' && |
| 145 | typeof target === 'string' && |
| 146 | /^[012]$/.test(target) |
| 147 | ) { |
| 148 | parts.push(`${entry}>&${target}`) |
| 149 | i += 2 |
| 150 | continue |
| 151 | } |
| 152 | |
| 153 | // Handle 2>/dev/null style redirections |
| 154 | if (op.op === '>' && target === '/dev/null') { |
| 155 | parts.push(`${entry}>/dev/null`) |
| 156 | i += 2 |
| 157 | continue |
| 158 | } |
| 159 | |
| 160 | // Handle 2> &1 style (space between > and &1) |
| 161 | if ( |
| 162 | op.op === '>' && |
| 163 | typeof target === 'string' && |
| 164 | target.startsWith('&') |
| 165 | ) { |
| 166 | const fd = target.slice(1) |
| 167 | if (/^[012]$/.test(fd)) { |
| 168 | parts.push(`${entry}>&${fd}`) |
| 169 | i += 2 |
| 170 | continue |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | // Handle regular entries |
| 176 | if (typeof entry === 'string') { |
no test coverage detected