MCPcopy Index your code
hub / github.com/codeaashu/claude-code / extractCompoundStructure

Function extractCompoundStructure

src/utils/bash/treeSitterAnalysis.ts:296–411  ·  view source on GitHub ↗
(
  rootNode: unknown,
  command: string,
)

Source from the content-addressed store, hash-verified

294 * Replaces isUnsafeCompoundCommand() and splitCommand() for tree-sitter path.
295 */
296export function extractCompoundStructure(
297 rootNode: unknown,
298 command: string,
299): CompoundStructure {
300 const n = rootNode as TreeSitterNode
301 const operators: string[] = []
302 const segments: string[] = []
303 let hasSubshell = false
304 let hasCommandGroup = false
305 let hasPipeline = false
306
307 // Walk top-level children of the program node
308 function walkTopLevel(node: TreeSitterNode): void {
309 for (const child of node.children) {
310 if (!child) continue
311
312 if (child.type === 'list') {
313 // list nodes contain && and || operators
314 for (const listChild of child.children) {
315 if (!listChild) continue
316 if (listChild.type === '&&' || listChild.type === '||') {
317 operators.push(listChild.type)
318 } else if (
319 listChild.type === 'list' ||
320 listChild.type === 'redirected_statement'
321 ) {
322 // Nested list, or redirected_statement wrapping a list/pipeline —
323 // recurse so inner operators/pipelines are detected. For
324 // `cmd1 && cmd2 2>/dev/null && cmd3`, the redirected_statement
325 // wraps `list(cmd1 && cmd2)` — the inner `&&` would be missed
326 // without recursion.
327 walkTopLevel({ ...node, children: [listChild] } as TreeSitterNode)
328 } else if (listChild.type === 'pipeline') {
329 hasPipeline = true
330 segments.push(listChild.text)
331 } else if (listChild.type === 'subshell') {
332 hasSubshell = true
333 segments.push(listChild.text)
334 } else if (listChild.type === 'compound_statement') {
335 hasCommandGroup = true
336 segments.push(listChild.text)
337 } else {
338 segments.push(listChild.text)
339 }
340 }
341 } else if (child.type === ';') {
342 operators.push(';')
343 } else if (child.type === 'pipeline') {
344 hasPipeline = true
345 segments.push(child.text)
346 } else if (child.type === 'subshell') {
347 hasSubshell = true
348 segments.push(child.text)
349 } else if (child.type === 'compound_statement') {
350 hasCommandGroup = true
351 segments.push(child.text)
352 } else if (
353 child.type === 'command' ||

Callers 1

analyzeCommandFunction · 0.85

Calls 2

walkTopLevelFunction · 0.85
pushMethod · 0.45

Tested by

no test coverage detected