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

Function walkVariableAssignment

src/utils/bash/ast.ts:1777–1922  ·  view source on GitHub ↗
(
  node: Node,
  innerCommands: SimpleCommand[],
  varScope: Map<string, string>,
)

Source from the content-addressed store, hash-verified

1775}
1776
1777function walkVariableAssignment(
1778 node: Node,
1779 innerCommands: SimpleCommand[],
1780 varScope: Map<string, string>,
1781): { name: string; value: string; isAppend: boolean } | ParseForSecurityResult {
1782 let name: string | null = null
1783 let value = ''
1784 let isAppend = false
1785
1786 for (const child of node.children) {
1787 if (!child) continue
1788 if (child.type === 'variable_name') {
1789 name = child.text
1790 } else if (child.type === '=' || child.type === '+=') {
1791 // `PATH+=":/new"` — tree-sitter emits `+=` as a distinct operator
1792 // node. Without this case it falls through to walkArgument below
1793 // → tooComplex on unknown type `+=`.
1794 isAppend = child.type === '+='
1795 continue
1796 } else if (child.type === 'command_substitution') {
1797 // $() as the variable's value. The output becomes a STRING stored in
1798 // the variable — it's NOT a positional argument (no path/flag concern).
1799 // `VAR=$(date)` runs `date`, stores output. `VAR=$(rm -rf /)` runs
1800 // `rm` — the inner command IS checked against permission rules, so
1801 // `rm` must match a rule. The variable just holds whatever `rm` prints.
1802 const err = collectCommandSubstitution(child, innerCommands, varScope)
1803 if (err) return err
1804 value = CMDSUB_PLACEHOLDER
1805 } else if (child.type === 'simple_expansion') {
1806 // `VAR=$OTHER` — assignment RHS does NOT word-split or glob-expand
1807 // in bash (unlike command arguments). So `A="a b"; B=$A` sets B to
1808 // the literal "a b". Resolve as if inside a string (insideString=true)
1809 // so BARE_VAR_UNSAFE_RE doesn't over-reject. The resulting value may
1810 // contain spaces/globs — if B is later used as a bare arg, THAT use
1811 // will correctly reject via BARE_VAR_UNSAFE_RE.
1812 const v = resolveSimpleExpansion(child, varScope, true)
1813 if (typeof v !== 'string') return v
1814 // If v is VAR_PLACEHOLDER (OTHER holds unknown), store it — combined
1815 // with containsAnyPlaceholder in the caller to treat as unknown.
1816 value = v
1817 } else {
1818 const v = walkArgument(child, innerCommands, varScope)
1819 if (typeof v !== 'string') return v
1820 value = v
1821 }
1822 }
1823
1824 if (name === null) {
1825 return {
1826 kind: 'too-complex',
1827 reason: 'Variable assignment without name',
1828 nodeType: 'variable_assignment',
1829 }
1830 }
1831 // SECURITY: tree-sitter-bash accepts invalid var names (e.g. `1VAR=value`)
1832 // as variable_assignment. Bash only recognizes [A-Za-z_][A-Za-z0-9_]* —
1833 // anything else is run as a COMMAND. `1VAR=value` → bash tries to execute
1834 // `1VAR=value` from PATH. We must not treat it as an inert assignment.

Callers 2

collectCommandsFunction · 0.85
walkCommandFunction · 0.85

Calls 4

resolveSimpleExpansionFunction · 0.85
walkArgumentFunction · 0.85
containsAnyPlaceholderFunction · 0.85

Tested by

no test coverage detected