Skip to main content
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:

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.
options.matches contains nodes that matched your selector (when getSelector is exported). Use them to short‑circuit or to avoid recomputing broad queries.
When you only need a stable repo-relative path for the current file, prefer root.relativeFilename() over manually stripping options.targetDir.

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.

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.
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
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.

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.

Constraint System

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

Traversal Control

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