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

# Transform APIs

> Transform contract, dynamic parsing, parser-backed edits, selectors, and rule composition.

How to shape the transform itself: the export contract, parsing other languages, AST edits, file selectors, and composable rules.

## Transform Function Contract

Every JSSG codemod must export a default function with this exact signature:

```ts theme={null}
import type { Codemod } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const codemod: Codemod<TSX> = async (root, options) => {
  // Your transformation logic
};

export default codemod;
```

### Transform Options

The `options` object provides execution context:

* `options.language: string` — language of the current file (e.g., `ts`, `tsx`). Use it to branch logic or choose language‑sensitive patterns.
* `options.params?: Record<string, string>` — user parameters defined in the workflow. Drive behavior switches, defaults, and environment‑specific choices.
* `options.matches?: any[]` — pre‑filtered nodes from the exported selector (if any). Use to skip broad queries inside the transform.
* `options.matrixValues?: Record<string, unknown>` — values from matrix strategy execution. Use for sharding, multi‑variant runs, or team‑scoped processing.
* `options.targetDir: string` — absolute target directory for the current run. Use it when you need the root path for resolving sibling files or reporting paths.

```ts theme={null}
import type { Codemod } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const codemod: Codemod<TSX> = async (root, options) => {
  const lang = options.language;
  const params = options.params;
  const preFilteredMatches = options.matches; // may be undefined if no selector
  const matrix = options.matrixValues; // undefined without matrix strategy
  const targetDir = options.targetDir;
  return null;
};

export default codemod;
```

<Info>
  `options.matches` contains nodes that matched your selector (when `getSelector` is exported). Use them to short‑circuit or to avoid recomputing broad queries.
</Info>

<Info>
  When you only need a stable repo-relative path for the current file, prefer `root.relativeFilename()` over manually stripping `options.targetDir`.
</Info>

## Dynamic Parsing

Dynamic parsing allows you to parse and analyze different types of code within a single transform. This is particularly powerful when working with embedded languages like CSS-in-JS, HTML templates, or SQL queries within JavaScript code.

Use dynamic parsing when your codemod needs to analyze multiple languages or when you're working with template literals containing different syntax.

```ts theme={null}
import { parseAsync } from "codemod:ast-grep";
import type { Codemod } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const codemod: Codemod<TSX> = async (root) => {
  // Find all styled-component template literals
  const styledComponents = root.root().findAll({
    rule: { pattern: "styled.$COMPONENT`$ARG`" }
  });

  for (const component of styledComponents) {
    const cssText = component.getMatch("ARG")?.text();
    if (!cssText) continue;

    // Parse the CSS content dynamically
    const cssRoot = await parseAsync("css", cssText);

    // Find vendor-prefixed properties that have modern equivalents
    const vendorPrefixedDeclarations = cssRoot.findAll({
      rule: {
        kind: "declaration",
        has: {
          kind: "property_name",
          regex: "^(-webkit-|-moz-|-ms-|-o-)"
        },
        inside: {
          kind: "block",
          has: {
            kind: "declaration",
            has: {
              kind: "property_name",
              regex: "^(border-radius|box-shadow|transition|transform|background|flex-direction)$"
            }
          }
        }
      },
    });

    // Log findings for analysis
    console.log(
      "Found vendor prefixes:",
      vendorPrefixedDeclarations.map((node) => node.text())
    );
  }

  return null;
};

export default codemod;
```

### Return Semantics

* **`string`**: Modified code (if identical to input, treated as unmodified)
* **`null`**: No changes needed
* **`undefined`**: Same as null
* **Other types**: Runtime error

## Parser-Backed Edits

Use AST-selected edits whenever the target file type has a JSSG parser. That includes source languages plus structured config formats such as JSON, YAML, XML, and TOML.

```ts theme={null}
import type { Codemod, Edit } from "codemod:ast-grep";
import type Toml from "codemod:ast-grep/langs/toml";

const codemod: Codemod<Toml> = async (root) => {
  const rootNode = root.root();
  const edits = rootNode
    .findAll({
      rule: {
        kind: "pair",
        has: { kind: "bare_key", regex: "^package-manager$" },
      },
    })
    .map((node) => node.replace('package-manager = "pnpm@9.0.0"'));

  return edits.length > 0 ? rootNode.commitEdits(edits as Edit[]) : null;
};

export default codemod;
```

Avoid using JSSG as a file walker while doing the actual transform with `fs`, `root.source().replace(...)`, or full-source `.split(...)`/`.join(...)` logic. Raw text rewriting is a fallback for unsupported plain-text formats or rare cases where no parser or structured library exists.

## Selectors (getSelector)

By default, JSSG processes every file in your project, which can be inefficient for large codebases.

When a selector is exported, you can pre-filter files based on specific patterns, so that the engine only calls your transform for files that match it.

* JSSG scans files using the selector before calling your transform
* Files without matches are skipped, reducing work
* Matched nodes are available via `options.matches`

```ts theme={null}
import type { GetSelector } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

export const getSelector: GetSelector<TSX> = () => ({
  rule: { any: [ { pattern: "console.log($$$ARGS)" }, { pattern: "console.warn($$$ARGS)" } ] }
});
```

<Info>
  If the selector finds no matches in a file, your transform is not invoked for that file. This reduces both file processing and runtime initialization overhead. Prefer selectors for broad filtering; use `find`/`findAll` inside the transform for precise node selection. Combine selectors with a discriminating source-text gate and never walk the rest of the repo per file. See [Performant codemods](/community/jssg/advanced/performance#performant-codemods).
</Info>

## Advanced Pattern Composition

### Rule References with Utils

Reference named sub‑rules in `utils` and attach them via `matches` to keep complex patterns DRY and composable.

```ts theme={null}
import type { RuleConfig } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const myRule: RuleConfig<TSX> = {
  rule: {
    matches: "jsx-element-hardcoded-human-language",
    inside: { pattern: "function $NAME()" }
  },
  utils: {
    "jsx-element-hardcoded-human-language": {
      any: [
        { kind: "jsx_element" },
        { kind: "jsx_self_closing_element" }
      ]
    }
  }
};
```

### Constraint System

Define reusable named fragments in `constraints` and reuse them across rules to centralize pattern logic.

```ts theme={null}
import type { RuleConfig } from "codemod:ast-grep";
import type TSX from "codemod:ast-grep/langs/tsx";

const stringLikeRule: RuleConfig<TSX> = {
  constraints: {
    STR: {
      any: [{ kind: "string" }, { kind: "template_string" }]
    },
    NUM: {
      kind: "number"
    }
  },
  utils: {
    "string-like": {
      any: [
        { matches: "STR" },
        { pattern: "$STR + $NUM" }
      ]
    }
  },
  rule: {
    matches: "string-like"
  }
};
```

### Traversal Control

Use `stopBy` to bound relational searches (e.g., to immediate neighbors or the end of a parent) for correctness and performance.

```ts theme={null}
// Search only immediate neighbors
{
  has: {
    stopBy: "neighbor",
    kind: "jsx_attribute"
  }
}

// Search until end of parent
{
  inside: {
    stopBy: "end",
    pattern: "function $NAME()"
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.