> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/nodejs/userland-migrations/llms.txt
> Use this file to discover all available pages before exploring further.

# AST-grep Utilities

> Core helper functions for working with AST nodes in Node.js codemods

Core utilities for working with AST nodes, including indentation detection, scope resolution, and code manipulation.

## Indentation Utilities

### detectIndentUnit

Detects the indentation unit used in source code (`\t` or spaces).

```typescript theme={null}
import { detectIndentUnit } from '@nodejs/codemod-utils/ast-grep/indent';

const indentUnit = detectIndentUnit(sourceCode);
// Returns: '\t' for tabs or '  ' for spaces (number of spaces determined by GCD)
```

<ParamField path="source" type="string" required>
  The source code to analyze
</ParamField>

**Returns**: `string` - The indentation unit (`'\t'` for tabs or a string of spaces)

<Note>
  The function analyzes all indented lines and uses the greatest common divisor (GCD) to determine the space-based indentation unit.
</Note>

### getLineIndent

Returns the indentation prefix for the line containing the given character index.

```typescript theme={null}
import { getLineIndent } from '@nodejs/codemod-utils/ast-grep/indent';

const indent = getLineIndent(sourceCode, node.range().start.index);
// Returns: '    ' (the leading whitespace for that line)
```

<ParamField path="source" type="string" required>
  The source code
</ParamField>

<ParamField path="index" type="number" required>
  The character index within the source code
</ParamField>

**Returns**: `string` - The indentation string (spaces or tabs) at the start of the line

## Scope Resolution

### getScope

Finds the enclosing scope for a node (e.g., `statement_block` or `program`).

```typescript theme={null}
import { getScope } from '@nodejs/codemod-utils/ast-grep/get-scope';

const scope = getScope(node);
// Returns: The nearest statement_block or program node

const customScope = getScope(node, 'function_declaration');
// Returns: The nearest function_declaration node
```

<ParamField path="node" type="SgNode<Js>" required>
  The AST node to find the scope for
</ParamField>

<ParamField path="customParent" type="string">
  Optional custom parent node type to stop at
</ParamField>

**Returns**: `SgNode<Js> | null` - The scope node or null if not found

## Shebang Utilities

### getShebang

Returns the Node.js shebang line node when present (e.g., `#!/usr/bin/env node`).

```typescript theme={null}
import { getShebang } from '@nodejs/codemod-utils/ast-grep/shebang';

const shebang = getShebang(ast);
if (shebang) {
  console.log(shebang.text()); // '#!/usr/bin/env node'
}
```

<ParamField path="rootNode" type="SgRoot" required>
  The root AST node to search
</ParamField>

**Returns**: `SgNode | null` - The shebang node if found, otherwise null

<Note>
  Only returns shebangs that appear at the start of the file (line 0) and contain "node" or "node.exe".
</Note>

### replaceNodeJsArgs (shebang)

Replaces Node.js arguments in shebang lines.

```typescript theme={null}
import { replaceNodeJsArgs } from '@nodejs/codemod-utils/ast-grep/shebang';

// Given: #!/usr/bin/env node --inspect
const edits = replaceNodeJsArgs(ast, { '--inspect': '' });
// Results in: #!/usr/bin/env node

const edits2 = replaceNodeJsArgs(ast, { '--inspect': '--inspect-brk' });
// Results in: #!/usr/bin/env node --inspect-brk
```

<ParamField path="rootNode" type="SgRoot" required>
  The root AST node to search
</ParamField>

<ParamField path="argsToValues" type="Record<string, string>" required>
  A mapping of argument names to their replacement values. Use empty string to remove an argument.
</ParamField>

**Returns**: `Edit[]` - Array of edit operations to apply

## Code Manipulation

### removeLines

Safely removes multiple line ranges from source code, handling overlaps and duplicates.

```typescript theme={null}
import { removeLines } from '@nodejs/codemod-utils/ast-grep/remove-lines';

const ranges = [
  { start: { line: 5, column: 0 }, end: { line: 5, column: 50 } },
  { start: { line: 12, column: 0 }, end: { line: 14, column: 0 } }
];

const cleanedCode = removeLines(sourceCode, ranges);
```

<ParamField path="sourceCode" type="string" required>
  The original source code as a single string
</ParamField>

<ParamField path="ranges" type="Range[]" required>
  An array of ranges to remove. Each range has `start` and `end` with `line` and `column` properties.
</ParamField>

**Returns**: `string` - The modified source code with the specified ranges removed

<Note>
  The function automatically handles duplicate and overlapping ranges by normalizing them before applying removals.
</Note>

## Import/Require Identifier Extraction

### getDefaultImportIdentifier

Returns the identifier node for a default `import` (e.g., `import fs from 'fs'`).

```typescript theme={null}
import { getDefaultImportIdentifier } from '@nodejs/codemod-utils/ast-grep/import-statement';

// Given: import fs from 'fs';
const id = getDefaultImportIdentifier(importNode);
console.log(id?.text()); // 'fs'
```

<ParamField path="importNode" type="SgNode<Js>" required>
  The `import_statement` or `import_clause` node
</ParamField>

**Returns**: `SgNode<Js> | null` - The identifier node for the default import, or null if none

### getRequireNamespaceIdentifier

Returns the identifier node for namespace-style `require` (e.g., `const util = require('util')`).

```typescript theme={null}
import { getRequireNamespaceIdentifier } from '@nodejs/codemod-utils/ast-grep/require-call';

// Given: const util = require('util');
const id = getRequireNamespaceIdentifier(varDeclaratorNode);
console.log(id?.text()); // 'util'

// Given: const { types } = require('util');
const id2 = getRequireNamespaceIdentifier(varDeclaratorNode);
console.log(id2); // null (destructured, not namespace)
```

<ParamField path="requireNode" type="SgNode<Js>" required>
  The `variable_declarator` node containing the require call
</ParamField>

**Returns**: `SgNode<Js> | null` - The identifier node for the namespace binding, or null for destructured requires

## Usage Examples

### Preserving Indentation When Adding Code

```typescript theme={null}
const indent = getLineIndent(sourceCode, node.range().start.index);
const indentUnit = detectIndentUnit(sourceCode);
const newCode = `${indent}${indentUnit}// New line\n${indent}${indentUnit}console.log('added');`;
```

### Finding and Modifying Shebang Lines

```typescript theme={null}
const shebang = getShebang(ast);
if (shebang && shebang.text().includes('--experimental-modules')) {
  const edits = replaceNodeJsArgs(ast, { '--experimental-modules': '' });
  context.applyEdits(edits);
}
```

### Cleaning Up Multiple Import Statements

```typescript theme={null}
const rangesToRemove = unusedImports.map(node => node.range());
const cleanedSource = removeLines(sourceCode, rangesToRemove);
context.writeFile('file.js', cleanedSource);
```
