# recast SyntaxError: Unexpected token - codemod parser chokes on newer syntax

TL;DR: Recast's default parser predates the newer syntax in your files. Tell recast to use its bundled Babel parser instead by passing `parser: require("recast/parsers/babel")` (or the `babel-ts` variant for TypeScript). Your transform logic is fine - only the parser needs swapping.

```text
recast SyntaxError: Unexpected token - codemod parser chokes on newer syntax
```

## Steps

1. Confirm it is the parser: the SyntaxError points at a modern feature (`?.`, `??`, class fields, TypeScript annotations) that your toolchain otherwise accepts.
   Expected: the flagged token is valid syntax in your project - the parser is the problem, not the code.
2. Swap the parser where you call `recast.parse`:
   ```
   const recast = require("recast");
   const ast = recast.parse(source, {
     parser: require("recast/parsers/babel-ts"),
   });
   ```
   Use `recast/parsers/babel` instead of `babel-ts` for plain JavaScript.
   Expected: parsing the same file now succeeds.
3. Keep using recast's printer for output - it preserves the original formatting; only the parser changes.
   Expected: output diffs look the same as before, the codemod just parses further.
4. Re-run the full codemod.
   Expected: no SyntaxError; files transform as intended.

## Use this when

- Recast throws `SyntaxError: Unexpected token` on syntax that is valid in your project.
- The codemod worked on older files but chokes after the codebase adopted newer syntax.
- The error comes from `recast.parse`, not from your transform logic.

## Not for this skill when

- The code is genuinely invalid - fix the code, not the parser.
- The `Unexpected token` comes from jscodeshift's own parser setup - different tool, different fix.
- The parse error is in the transform file itself rather than the files being transformed.

## Variant phrasings

- recast unexpected token optional chaining
- recast parse typescript files
- recast babel parser codemod

## Why it happens

Recast defaults to an older Esprima-based parser that predates modern syntax features. The Babel-based parsers bundled with recast understand current JavaScript and TypeScript, so pointing `parse` at them is the supported escape hatch.

## Edge cases

- `babel-ts` covers `.ts` and `.tsx`; plain `.js` with modern syntax wants the `babel` variant.
- For exotic proposals you may need to pass extra parser options through - check the parser module recast ships for the supported options shape.
- Parse with one parser and print with another and you can get reformatted output - keep both on recast to preserve formatting.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_DtvnLgYmLJkc51vn8FqOMg
