Skip to content

feat(tools-babel): Add tools-babel package for babel configuration and parsing support#4087

Open
JasonVMo wants to merge 9 commits intomainfrom
user/jasonvmo/tools-babel
Open

feat(tools-babel): Add tools-babel package for babel configuration and parsing support#4087
JasonVMo wants to merge 9 commits intomainfrom
user/jasonvmo/tools-babel

Conversation

@JasonVMo
Copy link
Copy Markdown
Collaborator

NOTE: this currently includes the tools-performance change as it depends on that change. Ignore those files here.

Description

This adds a tools project for dealing with babel with regards to react-native transformations. This builds upon some of the work from the metro-transformer-oxc package as well as some of the work I was looking at for using native tools for transformation.

This package has tools that deal with babel configuration and parsing.

Babel Configuration

Several utilities are provided here:

  • A central implementation of getting the babel configuration in a way compatible with what is in @react-native/metro-babel-transformer, which is the standard upstream babel transformer for react-native.
  • Helpers for parsing babel's plugin and preset types.
  • An implementation of the plugin visitor factory for instrumenting plugins.
  • A routine to update babel configs with a visitor pattern that is will only make changes if something is updated. It can be used to update plugins or remove them entirely.
  • A filter function for filtering plugins by key.

Babel Parsing

Parsing is one of the most time consuming and memory intensive parts of the transformation process. There are faster parsers but they generally produce estree ASTs rather than babel-ASTs. The current metro-transformer-oxc uses a utility estree-to-babel to convert the AST, which mostly works, but when timing the performance it ends up being almost as slow as babel parsing.

The parsing in here:

  • can parse with oxc, hermes-parser, or babel
  • has a reworked and heavily tuned AST converted that mutates in place, greatly reducing memory churn and making this drastically faster than hermes-parser end-to-end, which is itself substantially faster than babel.
  • uses a huge set of test fixtures (now in the @rnx-kit/test-fixtures package) to validate and test AST compatibility both at a raw level, as well as with generation and transformation.

The tests are fairly wordy for output but this is useful for allowing tools like Claude to gain information about what is happening and what the differences are.

@github-actions github-actions bot added the chore Improvements that don't directly affect features label Apr 13, 2026
| Domain | Frequency | What is traced |
| -------------- | --------- | ---------------------------------------------------- |
| `transform` | medium | Parse operations (OXC native, AST conversion, Babel) |
| `babel-plugin` | high | Individual plugin visitor method calls |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `babel-plugin` | high | Individual plugin visitor method calls |
| `babel-plugin` | high | Individual plugin visitor method calls |

Comment on lines +261 to +312
trackPerformance({ enable: "babel-plugin", strategy: "timing", frequency: "high" });
```

## TransformerSettings

Settings that persist across transformation passes:

| Field | Type | Default | Description |
| ---------------------- | -------------------------- | ------- | ------------------------------------------------------------ |
| `configCallerMixins` | `Record<string, string>` | -- | Extra fields added to Babel's `caller` config |
| `configDisabledPlugins`| `Set<string>` | -- | Plugin keys to remove from the resolved config |
| `parseDisableOxc` | `boolean` | -- | Disable OXC parser |
| `parseDisableHermes` | `boolean` | -- | Disable Hermes parser |
| `parseFlowDefault` | `boolean` | `true` | Assume Flow in `.js`/`.jsx` files under `node_modules` |
| `parseFlowWorkspace` | `boolean` | `false` | Assume Flow in workspace `.js`/`.jsx` files |
| `parseExtDefault` | `SrcSyntax` | `"js"` | Syntax for unknown file extensions (unset to skip) |
| `parseExtAliases` | `Record<string, SrcSyntax>`| -- | Map extensions to syntax types (e.g. `{ ".svg": "jsx" }`) |

## API Reference

### Config

| Function | Description |
| ------------------------------------- | -------------------------------------------------------------------------- |
| `getBabelConfig(args, settings?)` | Build a per-file Babel config from cached base config + file-specific settings |
| `filterConfigPlugins(config, disabled?)` | Resolve presets/overrides and filter plugins by key |

### Parsing

| Function | Description |
| ----------------------------- | -------------------------------------------------------------- |
| `parseToAst(args)` | Parse with fallback chain: OXC -> Hermes -> Babel |
| `oxcParseToAst(args, trace?)` | Parse with OXC and convert ESTree to Babel AST |
| `hermesParseToAst(args)` | Parse with Hermes |
| `toBabelAST(program, source, isTypeScript?, comments?)` | Convert OXC ESTree to Babel AST |

### Transformer

| Function | Description |
| ------------------------------------------------- | ------------------------------------------------------- |
| `makeTransformerArgs(babelArgs, settings?, updateContext?)` | Build `TransformerArgs` with context and Babel config |
| `initTransformerContext(filename, settings)` | Initialize file context without building Babel config |

### Plugins

| Function | Description |
| --------------------------------------- | --------------------------------------------------------------- |
| `isConfigItem(plugin)` | Check if plugin is a Babel `ConfigItem` |
| `isPluginObj(plugin)` | Check if plugin is a resolved `PluginObj` |
| `getPluginTarget(plugin)` | Extract the plugin target (function or string) |
| `getPluginKey(plugin)` | Extract the key from a resolved plugin |
| `updateTransformOptions(options, visitor)` | Walk and modify plugins/presets/overrides in a config |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
trackPerformance({ enable: "babel-plugin", strategy: "timing", frequency: "high" });
```
## TransformerSettings
Settings that persist across transformation passes:
| Field | Type | Default | Description |
| ---------------------- | -------------------------- | ------- | ------------------------------------------------------------ |
| `configCallerMixins` | `Record<string, string>` | -- | Extra fields added to Babel's `caller` config |
| `configDisabledPlugins`| `Set<string>` | -- | Plugin keys to remove from the resolved config |
| `parseDisableOxc` | `boolean` | -- | Disable OXC parser |
| `parseDisableHermes` | `boolean` | -- | Disable Hermes parser |
| `parseFlowDefault` | `boolean` | `true` | Assume Flow in `.js`/`.jsx` files under `node_modules` |
| `parseFlowWorkspace` | `boolean` | `false` | Assume Flow in workspace `.js`/`.jsx` files |
| `parseExtDefault` | `SrcSyntax` | `"js"` | Syntax for unknown file extensions (unset to skip) |
| `parseExtAliases` | `Record<string, SrcSyntax>`| -- | Map extensions to syntax types (e.g. `{ ".svg": "jsx" }`) |
## API Reference
### Config
| Function | Description |
| ------------------------------------- | -------------------------------------------------------------------------- |
| `getBabelConfig(args, settings?)` | Build a per-file Babel config from cached base config + file-specific settings |
| `filterConfigPlugins(config, disabled?)` | Resolve presets/overrides and filter plugins by key |
### Parsing
| Function | Description |
| ----------------------------- | -------------------------------------------------------------- |
| `parseToAst(args)` | Parse with fallback chain: OXC -> Hermes -> Babel |
| `oxcParseToAst(args, trace?)` | Parse with OXC and convert ESTree to Babel AST |
| `hermesParseToAst(args)` | Parse with Hermes |
| `toBabelAST(program, source, isTypeScript?, comments?)` | Convert OXC ESTree to Babel AST |
### Transformer
| Function | Description |
| ------------------------------------------------- | ------------------------------------------------------- |
| `makeTransformerArgs(babelArgs, settings?, updateContext?)` | Build `TransformerArgs` with context and Babel config |
| `initTransformerContext(filename, settings)` | Initialize file context without building Babel config |
### Plugins
| Function | Description |
| --------------------------------------- | --------------------------------------------------------------- |
| `isConfigItem(plugin)` | Check if plugin is a Babel `ConfigItem` |
| `isPluginObj(plugin)` | Check if plugin is a resolved `PluginObj` |
| `getPluginTarget(plugin)` | Extract the plugin target (function or string) |
| `getPluginKey(plugin)` | Extract the key from a resolved plugin |
| `updateTransformOptions(options, visitor)` | Walk and modify plugins/presets/overrides in a config |
trackPerformance({
enable: "babel-plugin",
strategy: "timing",
frequency: "high",
});

TransformerSettings

Settings that persist across transformation passes:

Field Type Default Description
configCallerMixins Record<string, string> -- Extra fields added to Babel's caller config
configDisabledPlugins Set<string> -- Plugin keys to remove from the resolved config
parseDisableOxc boolean -- Disable OXC parser
parseDisableHermes boolean -- Disable Hermes parser
parseFlowDefault boolean true Assume Flow in .js/.jsx files under node_modules
parseFlowWorkspace boolean false Assume Flow in workspace .js/.jsx files
parseExtDefault SrcSyntax "js" Syntax for unknown file extensions (unset to skip)
parseExtAliases Record<string, SrcSyntax> -- Map extensions to syntax types (e.g. { ".svg": "jsx" })

API Reference

Config

Function Description
getBabelConfig(args, settings?) Build a per-file Babel config from cached base config + file-specific settings
filterConfigPlugins(config, disabled?) Resolve presets/overrides and filter plugins by key

Parsing

Function Description
parseToAst(args) Parse with fallback chain: OXC -> Hermes -> Babel
oxcParseToAst(args, trace?) Parse with OXC and convert ESTree to Babel AST
hermesParseToAst(args) Parse with Hermes
toBabelAST(program, source, isTypeScript?, comments?) Convert OXC ESTree to Babel AST

Transformer

Function Description
makeTransformerArgs(babelArgs, settings?, updateContext?) Build TransformerArgs with context and Babel config
initTransformerContext(filename, settings) Initialize file context without building Babel config

Plugins

Function Description
isConfigItem(plugin) Check if plugin is a Babel ConfigItem
isPluginObj(plugin) Check if plugin is a resolved PluginObj
getPluginTarget(plugin) Extract the plugin target (function or string)
getPluginKey(plugin) Extract the key from a resolved plugin
updateTransformOptions(options, visitor) Walk and modify plugins/presets/overrides in a config

@JasonVMo JasonVMo force-pushed the user/jasonvmo/tools-babel branch from 1ab7c49 to d67e42a Compare April 13, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Improvements that don't directly affect features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant