---
title: "Oxlint v1.72 and Oxfmt v0.57 Land the v0.138 Crates Cycle, Unify the AstBuilder, and Retire the Prettier CSS/GraphQL Fallback"
description: "Oxlint apps_v1.72.0 and oxfmt apps_v0.57.0, both published on 2026-06-29, close out the v0.138 crates cycle predicted in the [v1.71 release notes](/articles/2026-06-23--oxlint-v1-71-oxfmt-v0-56). The crates release (crates_v0.138.0, also 2026-06-29) unifies the old and new AstBuilder APIs (#23876, #23834, #23831, with legacy methods marked `#[deprecated]`), renames `AllocatorAccessor` to `GetAllocator` and switches its `allocator` method to take `&self` (#23675, #23676), makes `Str` and `Ident` methods take `&GetAllocator` (#23781), adds `transformer_plugins: Support typeof define keys` for vue-i18n and similar macros (#23605, Alexander Lichter), and ships the headline perf entry of the cycle: `minifier: memoize value_type to remove its O(n^2) re-walk on long binary chains` (#23929, Dunqing), which turns a 20k-term arithmetic-addition chain from 6,118 ms to 4.7 ms (~1300x) and a real-world antd.js bundle from 78.1 ms to 65.4 ms. Oxlint v1.72.0 ships 3 features (React `no-unknown-property` suggestion #23936, AstBuilder unification #23875, `eslint/no-restricted-import` schema #23642), 18 bug fixes, and 23 performance entries. Oxfmt v0.57.0 carries two BREAKING changes that retire the Prettier fallback for CSS/LESS/SCSS and GraphQL files: `Format parser:css,less,scss files + css-in-js by oxc_formatter_css` (#23321, leaysgur) and `Support draft syntax with removing prettier fallback` (#23326, leaysgur), both landing on top of the new `oxc_formatter_css` (#23320) and `oxc_formatter_graphql` (#23317) crates."
date: 2026-06-30
image: "/images/heroes/2026-06-30--oxlint-v1-72-oxfmt-v0-57-ast-builder-css-graphql-native.png"
author: lschvn
tags: ["tooling", "performance"]
tldr:
  - "[Oxlint v1.72.0](https://github.com/oxc-project/oxc/releases/tag/apps_v1.72.0) and [oxfmt v0.57.0](https://github.com/oxc-project/oxc/releases/tag/apps_v1.72.0) shipped together on June 29, 2026, on top of [crates_v0.138.0](https://github.com/oxc-project/oxc/releases/tag/crates_v0.138.0). The Oxc release carries six BREAKING API changes, all in the Rust-side `oxc_ast` / `oxc_allocator` / `oxc_ecmascript` crates: the old and new `AstBuilder`s are unified behind a single `AstBuilder` export with the legacy methods marked `#[deprecated]` (#23876, #23834, #23831, #23877), `AllocatorAccessor` is renamed to `GetAllocator` (#23675), `GetAllocator::allocator` takes `&self` (#23676), and `Str` / `Ident` methods take `&GetAllocator` (#23781). These break downstream crates that build custom ASTs on top of Oxc but do not affect oxlint / oxfmt users."
  - "The single largest user-visible perf entry of the cycle is [PR #23929](https://github.com/oxc-project/oxc/pull/23929) (Dunqing): `perf(minifier): memoize value_type to remove its O(n^2) re-walk on long binary chains`. The minifier's post-order peephole used to evaluate `Expression::value_type` at every node and re-walk the entire left subtree on every binary chain, so a 20,000-term `a + a + … + a` took ~6,118 ms. Memoizing `value_type` by node address turns the same input into 4.7 ms (≈1300x), the 4,000-term variant from 234 ms to 0.9 ms (4.07x → 2.09x scaling), and antd.js from 78.1 ms to 65.4 ms. The cache lives on `MinifierState` and is opt-in via hooks on `GlobalContext`, so every non-minifier caller keeps the previous, uncached behaviour."
  - "[Oxfmt v0.57.0](https://github.com/oxc-project/oxc/releases/tag/apps_v1.72.0) retires the Prettier fallback for CSS / LESS / SCSS and for GraphQL files via two BREAKING changes: `Format parser:css,less,scss files + css-in-js by oxc_formatter_css` (#23321, leaysgur) and `Support draft syntax with removing prettier fallback` (#23326, leaysgur), both on top of the new `oxc_formatter_css` (#23320) and `oxc_formatter_graphql` (#23317) crates. This continues the same theme as the [Prettier 3.9 release notes](/articles/2026-06-28--prettier-3-9-micromark-yaml-graphql-rust-flow-parser) on June 28, where Prettier adopted the Oxc parsers for GraphQL, Markdown, and Flow; Oxfmt now closes the loop by writing CSS / SCSS / GraphQL back out without leaving Rust."
faq:
  - question: "What is the headline of the Oxc v0.138 crates release?"
    answer: "Six breaking changes concentrated in the Rust-side `oxc_ast` / `oxc_allocator` / `oxc_ecmascript` crates, all part of a single unifying story: the old and new `AstBuilder`s collapse into one. PR #23876 (overlookmotel) restricts the `oxc_ast::builder` module to exporting only the `AstBuilder` type and the `NONE` sentinel; #23834 (overlookmotel) switches `oxc_ecmascript` to the new `AstBuilder`; #23831 (overlookmotel) switches the transformer to the new `AstBuilder`; #23875 (overlookmotel) removes the in-tree duplication by unifying the builders; and #23877 marks the legacy `AstBuilder` methods `#[deprecated]`. The allocator side gets `AllocatorAccessor` renamed to `GetAllocator` (#23675) and `GetAllocator::allocator` switched to `&self` (#23676). The str side gets `Str` and `Ident` methods taking `&GetAllocator` (#23781). Downstream crates that build custom ASTs on top of Oxc have to update their call sites; oxlint and oxfmt users see no change because the apps already sit on top of the unified builder."
  - question: "Why is the AstBuilder unification a big deal?"
    answer: "Before v0.138 the Oxc tree shipped two parallel AST builders: a 'legacy' builder kept for callers that had not migrated, and the newer builder that the `oxc_ecmascript` and transformer crates had moved to. The two builders duplicated logic for every node type, doubled the maintenance surface for the parser, and forced every contributor to pick a side. The v0.138 unification finishes the migration: there is one `AstBuilder`, the legacy methods are marked `#[deprecated]` (#23877), and the in-tree crates that still used the legacy builder (the transformer and `oxc_ecmascript`) are switched over (#23831, #23834). The `oxc_ast` crate also gets a `disable_old_builder` Cargo feature flag for tests (#23888, #23886), so downstream crates that need to migrate can flip the flag and see what breaks. The change is invisible to JS / TS users of oxlint and oxfmt; it is very visible to anyone building a custom AST layer on top of Oxc."
  - question: "How fast is the new `value_type` memoization?"
    answer: "The headline numbers from PR #23929 (Dunqing): a 4,000-term arithmetic-addition chain `a + a + … + a` drops from 234 ms to 0.9 ms (4.07x scaling → 2.09x scaling, i.e. O(n²) → O(n)), an 8,000-term chain drops from 953 ms to 1.9 ms, a 20,000-term chain drops from 6,118 ms to 4.7 ms (≈1300x), and the real-world antd.js bundle drops from 78.1 ms to 65.4 ms. The cache is keyed by node address and lives on `MinifierState`; it is invalidated at the single mutation chokepoint (`record_mutation`, hit by every `replace_*` / `drop_*`) and at each per-pass reset. The cache is exposed as opt-in hooks on `GlobalContext` (`cached_value_type` / `cache_value_type`); only the minifier's `TraverseCtx<MinifierState>` supplies a real cache, so every non-minifier caller (constant-evaluation, side-effects, the `value_type` unit harness, `WithoutGlobalReferenceInformation`) keeps the exact previous, uncached behaviour."
  - question: "What does the Oxfmt v0.57 Prettier-fallback removal actually change?"
    answer: "Before v0.57, oxfmt could format CSS / LESS / SCSS and GraphQL files, but it did so by shelling out to a bundled Prettier for those grammars. v0.57 retires the Prettier fallback for both grammars and formats them natively in Rust. The CSS side lands as `oxc_formatter_css` (#23320, leaysgur) and is wired in via the BREAKING entry `Format parser:css,less,scss files + css-in-js by oxc_formatter_css` (#23321, leaysgur); the GraphQL side lands as `oxc_formatter_graphql` (#23317) and is wired in via the BREAKING entry `Support draft syntax with removing prettier fallback` (#23326, leaysgur). The release notes flag the css-in-js path as supported through the new formatter (i.e. `styled-components` / Emotion-style template literals are now formatted by Oxc, not Prettier). Two prettier-diff parity PRs (#23327 for CSS, #23419 for GraphQL) bring the output closer to Prettier's, but the projects still expect real-world diffs on existing codebases. Combined with the CSS frontmatter language fix (#23819) and the printable-ASCII fast path in `TextWidth` (#23913), v0.57 is the release where oxfmt is no longer a 'JS/TS formatter with a Prettier sidecar for the rest'."
  - question: "What new linter rules or schema entries land in Oxlint v1.72.0?"
    answer: "Three new features and one schema. The headline rule change is `linter/react: Implement suggestion for no-unknown-property` (#23936, Mikhail Baev), which adds a Quick Fix to the React `no-unknown-property` rule so editors can rename the property in place; before v1.72 the rule only reported the issue. The headline infrastructure change is `ast: Unify old and new AstBuilders` (#23875, overlookmotel), the same unification that powers the v0.138 crates release. The third feature is `linter: Add schema for eslint/no-restricted-import` (#23642, Sysix), which lets users express the `paths` and `patterns` arrays of `no-restricted-import` through the config schema rather than the raw JSON. The rest of v1.72 is 18 bug fixes (most of them Yunfei He's fixer-rewrite work; the standout is the `linter/prefer-called-exactly-once-with: Avoid out-of-bounds slice panic at end of file` fix #23625) and 23 performance entries, including `linter/jsx-a11y: Skip lowercasing non-aria attribute names` (#23906, Lawrence Lin), `linter/typescript/no-unsafe-declaration-merging: Use keyed binding lookup` (#23894, Marius Schulz), `linter/eslint/no-unused-vars: Precompute exported bindings` (#23881, camc314), and the new `linter: Skip traversal without this expressions` (#23845, camc314) which short-circuits a class of rules when there are no `this`-expressions in the file."
  - question: "Why does the typeof define keys feature matter for Vue?"
    answer: "PR #23605 by Alexander Lichter (the maintainer of vue-router and a frequent Vue compiler contributor) adds support for `typeof` keys inside the `define` macro pattern that Vue's compiler-macros plugin matches on. Vue's `defineProps`, `defineEmits`, and friends accept a runtime form (`defineProps<typeof import('./foo').bar>()`) and the previous transformer_plugins implementation did not recognize that shape. After v0.138, the `transformer_plugins` crate matches `typeof` keys as a sub-pattern of the macro body, so the resulting TypeScript code keeps its type imports through macro expansion. The same machinery is shared by vue-i18n's `defineI18nLocale` and the macro patterns in Nuxt's auto-imports; the typeof support unblocks a long-standing issue in the `vue-i18n` ecosystem and is the first Oxc-side change of the cycle with a Vue contributor on the PR."
  - question: "Does the v0.138 crates release ship any other notable perf work?"
    answer: "Yes. The five perf entries besides the `value_type` memoization that stand out: `semantic: Flatten hoisting_variables to avoid per-scope map allocation` (#23927, Lawrence Lin), which removes a per-scope map allocation on every hoisted-variable update; `isolated-declarations: Pool scope maps to avoid per-scope alloc/rehash` (#23761, Boshen), which pools the scope maps used by isolated-declarations to avoid the alloc / rehash on every function; `minifier: Bail member-expr folding before the side-effect walk` (#23924, Lawrence Lin), which folds the cheap cases of `a.b.c.d` chains before the side-effect walk; `parser: Avoid span lookup for arrow expression body` (#23788, camc314); and `formatter_core: Add printable-ASCII fast path to TextWidth` (#23913, Lawrence Lin), which gives the formatter's line-width computation a fast path when the text contains only printable ASCII. On the parser side the largest perf entry is `parser: Allocate AST nodes in arena directly` (#23712, overlookmotel), part of a three-PR cluster (#23710 in minifier, #23709 in isolated-declarations, plus the parser PR) that moves AST node allocation out of `Box::new_in` into a direct arena allocation."
  - question: "Is the v0.138 cycle a good time to migrate to Oxlint / Oxfmt?"
    answer: "For JS / TS users the migration has been steady-state for several cycles and v1.72 / v0.57 are no different: the CLI surface, the config schema, and the rules are unchanged; the v1.72 perf gains land automatically; and the Oxfmt v0.57 breaking changes are restricted to the Rust API. The biggest argument for migrating to oxfmt in v0.57 specifically is the Prettier-fallback removal: CSS / LESS / SCSS / css-in-js and GraphQL are now formatted by Oxc's own Rust implementation rather than a bundled Prettier, which closes a long-standing gap. The argument against migrating is unchanged from previous cycles: any rule that lives in ESLint and has not yet been ported to oxlint still needs an ESLint pass. The official `migrate-from-prettier` guide and the `migrate-from-eslint` guide cover the workflow; the Oxfmt `--migrate prettier` command (touched up in #23963 this cycle) does the bulk of the config translation."
---

[Oxlint apps_v1.72.0](https://github.com/oxc-project/oxc/releases/tag/apps_v1.72.0) and [oxfmt apps_v0.57.0](https://github.com/oxc-project/oxc/releases/tag/apps_v1.72.0) shipped together on the evening of June 29, 2026, on top of [crates_v0.138.0](https://github.com/oxc-project/oxc/releases/tag/crates_v0.138.0). The release is the v0.138 cycle that the [v1.71 release notes](/articles/2026-06-23--oxlint-v1-71-oxfmt-v0-56) explicitly predicted: "the last [apps release] before the v0.138 crates release that will land on Monday 2026-06-29." The cycle finishes the AstBuilder migration that has been running across the v0.135 through v0.137 releases, retires the Prettier fallback for CSS / LESS / SCSS and GraphQL in oxfmt, and ships the largest single perf entry of the v0.137 → v0.138 stretch: the `value_type` memoization that turns a 20,000-term arithmetic-addition chain from 6.1 seconds to 4.7 milliseconds.

This article covers the Oxlint v1.72.0 apps release, the Oxfmt v0.57.0 apps release, and the crates_v0.138.0 release together because the three are designed to ship as one. Oxlint and oxfmt pull the latest crates line at release time, and the breaking changes in this cycle are concentrated in the crates layer.

## AstBuilder unification: the v0.135 → v0.138 migration lands

The biggest story of the v0.138 cycle is the unification of the old and new `AstBuilder` APIs in the `oxc_ast` crate. The migration has been running since at least v0.135 in early June and is the largest internal API change Oxc has done since the minifier rewrite.

The pattern is five PRs in this release that move the API surface to a single builder. [#23876](https://github.com/oxc-project/oxc/pull/23876) (overlookmotel) restricts the `oxc_ast::builder` module to exporting only the `AstBuilder` type and the `NONE` sentinel. [#23834](https://github.com/oxc-project/oxc/pull/23834) (overlookmotel) switches `oxc_ecmascript` to the new `AstBuilder`. [#23831](https://github.com/oxc-project/oxc/pull/23831) (overlookmotel) switches the transformer to the new `AstBuilder`. [#23875](https://github.com/oxc-project/oxc/pull/23875) (overlookmotel) removes the in-tree duplication by unifying the builders. [#23877](https://github.com/oxc-project/oxc/pull/23877) (overlookmotel) marks the legacy `AstBuilder` methods `#[deprecated]`. The cycle also adds an `oxc_ast` Cargo feature flag `disable_old_builder` (#23886, #23888) so downstream crates can flip the flag and see what breaks before the legacy methods are removed.

The allocator side gets its own batch of changes. [#23675](https://github.com/oxc-project/oxc/pull/23675) (overlookmotel) renames the `AllocatorAccessor` trait to `GetAllocator`. [#23676](https://github.com/oxc-project/oxc/pull/23676) (overlookmotel) switches `GetAllocator::allocator` to take `&self` instead of `self`. [#23781](https://github.com/oxc-project/oxc/pull/23781) (overlookmotel) makes `Str` and `Ident` methods take `&GetAllocator`. Together, the three changes finish the migration to a borrowing allocator API: callers no longer need to clone or own an allocator to build strings and identifiers.

For oxlint and oxfmt users, none of this is visible. For downstream crates that build custom AST layers on top of Oxc, this is the largest breaking change in three cycles. The release notes flag the migration window: legacy methods carry `#[deprecated]` annotations now, will compile with warnings, and will be removed in a future cycle. The team has been signalling this for two cycles, with the v0.137 release notes already warning about the breaking change in `oxc_ast`.

## The headline perf entry: `value_type` memoization turns O(n²) into O(n)

The single largest user-visible perf entry in v0.138 is [PR #23929](https://github.com/oxc-project/oxc/pull/23929) (Dunqing): `perf(minifier): memoize value_type to remove its O(n^2) re-walk on long binary chains`. The minifier's post-order peephole evaluates `Expression::value_type` at every node, and on a long left-associative binary chain the evaluation re-walks the entire left subtree (`to_primitive` → `value_type` → `to_primitive` → …). For N nodes the total cost was O(N²), and the dominant case is non-foldable arithmetic-addition chains: a 20,000-term `a + a + … + a` took 6,118 ms to minify while the parse and semantic phases were linear.

The fix memoizes `value_type` by node address on `MinifierState`, with one cut point at the recursive `Expression::value_type` method. Each node is computed once, so the total cost becomes O(N) amortized. The cache is exposed as opt-in hooks on `GlobalContext` (`cached_value_type` / `cache_value_type`), and only the minifier's `TraverseCtx<MinifierState>` supplies a real cache. Every other caller (`WithoutGlobalReferenceInformation`, the constant-evaluation pass, side-effects analysis, the `value_type` unit harness) keeps the exact previous, uncached behaviour. The cache is cleared at the single mutation chokepoint (`record_mutation`, hit by every `replace_*` / `drop_*`) and at each per-pass reset.

The numbers, straight from the PR description:

| input | before | after | effect |
| --- | ---: | ---: | --- |
| `a + a + …` × 4,000 | 234 ms | 0.9 ms | scaling 4.07x → 2.09x (O(n²) → O(n)) |
| `a + a + …` × 8,000 | 953 ms | 1.9 ms | linear from here on |
| `a + a + …` × 20,000 | 6,118 ms | 4.7 ms | ≈1300x faster |
| antd.js (real code) | 78.1 ms | 65.4 ms | ≈16% faster on real input |

The takeaway is that arithmetic-addition chains on minified output (the kind that show up in generated numeric code and in big polyfills) drop by three orders of magnitude. Real-world bundles drop by 16% on the first run, with the gains compounding on larger inputs.

The cycle has five other perf entries worth flagging. [`semantic: Flatten hoisting_variables to avoid per-scope map allocation`](https://github.com/oxc-project/oxc/pull/23927) (Lawrence Lin) removes the per-scope map allocation that fired on every hoisted-variable update. [`isolated-declarations: Pool scope maps to avoid per-scope alloc/rehash`](https://github.com/oxc-project/oxc/pull/23761) (Boshen) pools the scope maps used by `oxc_isolated_declarations` so the per-function alloc / rehash is gone. [`minifier: Bail member-expr folding before the side-effect walk`](https://github.com/oxc-project/oxc/pull/23924) (Lawrence Lin) folds the cheap cases of `a.b.c.d` chains before the side-effect walk. [`parser: Avoid span lookup for arrow expression body`](https://github.com/oxc-project/oxc/pull/23788) (camc314) drops one hashmap lookup per arrow expression. On the formatter side, [`formatter_core: Add printable-ASCII fast path to TextWidth`](https://github.com/oxc-project/oxc/pull/23913) (Lawrence Lin) gives the formatter's line-width computation a fast path when the text is pure printable ASCII, which covers the vast majority of formatted output.

There is also a cluster of three PRs that move AST node allocation out of `Box::new_in` into a direct arena allocation: [`parser: Allocate AST nodes in arena directly`](https://github.com/oxc-project/oxc/pull/23712) (overlookmotel), [`minifier: Allocate AST nodes in arena directly`](https://github.com/oxc-project/oxc/pull/23710) (overlookmotel), and [`isolated_declarations: Allocate AST nodes in arena directly`](https://github.com/oxc-project/oxc/pull/23709) (overlookmotel). Together they replace the `Box::new_in` indirection with a direct bump-allocator write, removing one heap allocation per AST node in the parser, the minifier, and the isolated-declarations pipeline.

## Oxfmt v0.57 retires the Prettier fallback for CSS / LESS / SCSS / GraphQL

The biggest structural change in oxfmt is the retirement of the Prettier fallback for the CSS and GraphQL grammars. Before v0.57, oxfmt could format CSS / LESS / SCSS files and GraphQL files, but it did so by shelling out to a bundled Prettier for those grammars. v0.57 retires the fallback and formats both grammars natively in Rust.

The CSS side lands as [`oxc_formatter_css`](https://github.com/oxc-project/oxc/pull/23320) (leaysgur) and is wired in via the BREAKING entry [`Format parser:css,less,scss files + css-in-js by oxc_formatter_css`](https://github.com/oxc-project/oxc/pull/23321) (leaysgur). The crate is a standalone formatter implementation that takes the existing CSS / LESS / SCSS parsers, walks the AST, and emits Prettier-compatible output. The release notes explicitly call out css-in-js as supported: `styled-components` and Emotion-style template literals, which oxfmt already detects and routes to the CSS parser, are now formatted by `oxc_formatter_css` rather than the Prettier shim.

The GraphQL side lands as [`oxc_formatter_graphql`](https://github.com/oxc-project/oxc/pull/23317) (leaysgur) and is wired in via the BREAKING entry [`Support draft syntax with removing prettier fallback`](https://github.com/oxc-project/oxc/pull/23326) (leaysgur). The "draft syntax" part is the part that is genuinely new: oxfmt's previous GraphQL implementation handled the stable 2021 spec; the new one handles the GraphQL October 2021 draft syntax and the working-draft syntax used by Apollo Federation and Yoga. This is a real feature, not just a rename: the Prettier fallback could not handle the draft syntax either, so the upgrade also closes a real format-on-save gap for users on Apollo's stack.

Two prettier-diff parity PRs bring the new formatters' output closer to Prettier's: [`formatter_css: Improve major prettier diffs`](https://github.com/oxc-project/oxc/pull/23327) (leaysgur) and [`formatter_graphql: Improve major prettier diffs`](https://github.com/oxc-project/oxc/pull/23419) (leaysgur). The release notes flag that real-world diffs on existing codebases are still expected (the typical 'first run changes a few lines, subsequent runs are idempotent' pattern), but the gap is much smaller than it was at v0.56.

The release also adds [`formatter_css: Handle frontmatter language`](https://github.com/oxc-project/oxc/pull/23819) (leaysgur), which routes Markdown frontmatter in CSS files (e.g. the `---` block at the top of a Vue SFC's `<style>` block when it has frontmatter metadata) to the frontmatter parser rather than treating it as CSS, and the printable-ASCII fast path in `TextWidth` mentioned above.

The broader picture is that oxfmt is no longer a 'JS / TS formatter with a Prettier sidecar for everything else.' After v0.57 the JS / TS / JSON / JSONC paths stay on the in-tree formatter (which has been on its own since v0.54), and CSS / LESS / SCSS / css-in-js and GraphQL join them. The remaining grammars Prettier handles (Markdown, YAML, HTML) are not in scope for oxfmt; oxfmt explicitly leaves them to Prettier and to the [Prettier 3.9 Rust parsers](/articles/2026-06-28--prettier-3-9-micromark-yaml-graphql-rust-flow-parser) that landed June 27.

The cycle also touches the migrate command: [`fix(oxfmt): update --migrate prettier`](https://github.com/oxc-project/oxc/pull/23963) (leaysgur) cleans up the Prettier → oxfmt config migration command to handle the new in-tree CSS / GraphQL formatters. The command remains the recommended path for bringing an existing Prettier config into an oxfmt project; the v0.57 update adds the new grammars to the conversion table.

## Oxlint v1.72 features and the perf dump

The Oxlint v1.72.0 apps release ships three features, eighteen bug fixes, and twenty-three performance entries on top of crates_v0.138.0. The headline feature is [`linter/react: Implement suggestion for no-unknown-property`](https://github.com/oxc-project/oxc/pull/23936) (Mikhail Baev), which adds a Quick Fix to the React `no-unknown-property` rule. Before v1.72 the rule reported the issue without a code action; editors would flag the property as unknown but the developer had to rename it manually. After v1.72 the editor can offer an in-place rename to the closest known property.

The second feature is [`ast: Unify old and new AstBuilders`](https://github.com/oxc-project/oxc/pull/23875) (overlookmotel), the same unification that powers the crates_v0.138.0 release. The apps side flips the import path to the unified `AstBuilder`, which is what the rule work in this cycle builds on.

The third feature is [`linter: Add schema for eslint/no-restricted-import`](https://github.com/oxc-project/oxc/pull/23642) (Sysix). The schema lets users express the `paths` and `patterns` arrays of `no-restricted-import` through the config schema rather than raw JSON, which closes a long-standing gap in the ESLint → oxlint config migration path.

Eighteen bug fixes range from corner-case false positives to panic-prevention fixes. The standout is [`linter/prefer-called-exactly-once-with: Avoid out-of-bounds slice panic at end of file`](https://github.com/oxc-project/oxc/pull/23625) (Jerry Zhao), which closed a real panic that could crash the linter on test files where the assertion was the last expression. Other notable fixes: [`linter/unicorn/custom-error-definition: Handle non-ascii class names`](https://github.com/oxc-project/oxc/pull/23939) (camc314), [`linter/eslint/no-negated-condition: Add autofix for negated conditions`](https://github.com/oxc-project/oxc/pull/23825) (Yagiz Nizipli), [`linter/eslint/prefer-destructuring: Skip AssignmentExpression autofixes`](https://github.com/oxc-project/oxc/pull/23818) (camc314), and [`linter/eslint/no-restricted-globals: Handle shadowed locals`](https://github.com/oxc-project/oxc/pull/23736) (camc314).

Twenty-three performance entries continue the v1.71 bucketed-dispatch story. The headline entries: [`linter/jsx-a11y: Skip lowercasing non-aria attribute names`](https://github.com/oxc-project/oxc/pull/23906) (Lawrence Lin), which removes one `to_ascii_lowercase` allocation per JSX attribute; [`linter/typescript/no-unsafe-declaration-merging: Use keyed binding lookup`](https://github.com/oxc-project/oxc/pull/23894) (Marius Schulz), which replaces a linear lookup with the same keyed-binding table the v1.71 bucketed dispatch introduced; [`linter/eslint/no-unused-vars: Precompute exported bindings`](https://github.com/oxc-project/oxc/pull/23881) (camc314); [`linter/unicorn/prefer-number-properties: Speed up global checks`](https://github.com/oxc-project/oxc/pull/23880) (camc314); [`linter/eslint/no-script-url: Match javascript: prefix without allocating`](https://github.com/oxc-project/oxc/pull/23861) (Lawrence Lin); and [`linter: Skip traversal without this expressions`](https://github.com/oxc-project/oxc/pull/23845) (camc314), which short-circuits a class of rules when there are no `this`-expressions in the file at all. Together with the v1.71 bucketed-dispatch baseline, the v1.72 perf entries put oxlint at the point where most rules' wall time is dominated by tree traversal, not by rule-internal allocation churn.

The linter bug fixes also include [`linter/jsx-a11y/role-supports-aria-props: Ignore nullish prop values`](https://github.com/oxc-project/oxc/pull/23865) (Mikhail Baev) and [`linter/eslint/no-warning-comments: Avoid dropping generated regex patterns`](https://github.com/oxc-project/oxc/pull/23741) (camc314), both of which close false-positive gaps on real-world JSX. The lsp side gets [`lsp: Normalize user config path to watch pattern`](https://github.com/oxc-project/oxc/pull/23723) (Sysix), which fixes a long-standing LSP path-resolution bug on Windows.

## The Vue typeof define keys feature

[PR #23605](https://github.com/oxc-project/oxc/pull/23605) by Alexander Lichter adds `transformer_plugins: Support typeof define keys`. The PR adds support for `typeof` keys inside the `define` macro pattern that Vue's compiler-macros plugin matches on. Vue's `defineProps`, `defineEmits`, `defineModel`, `defineSlots`, and friends accept a runtime form (`defineProps<typeof import('./foo').bar>()`), and the previous transformer_plugins implementation did not recognize that shape. After v0.138, the `transformer_plugins` crate matches `typeof` keys as a sub-pattern of the macro body, so the resulting TypeScript code keeps its type imports through macro expansion.

The pattern is shared by the Vue ecosystem macros that sit on top of `defineProps`. vue-i18n's `defineI18nLocale` and `defineI18nRoute`, Nuxt's auto-imports macros (`defineNuxtConfig`, `defineNuxtPlugin`), and the macro patterns in pinia's setup stores all accept a `typeof import(...)` reference inside the macro body. Before this PR, the transformer would either fail to match the macro (the fallback path generated the macro as a no-op call) or, worse, treat the `typeof` token as a value and break the type import tracking.

The PR is also the first Oxc-side change of the v0.138 cycle with a Vue ecosystem contributor on it. Alexander Lichter is the maintainer of vue-router and a frequent contributor to the Vue compiler macros conversation; the typeof support unblocks a long-standing issue in the vue-i18n ecosystem and is the clearest signal in this cycle that the transformer_plugins surface is moving toward being usable on real Vue codebases without an upstream `vue-tsc` pass.

## What to watch

Three signals for the next two to three weeks. First, watch for the v0.138.1 patch line and for any backward-compat issue reports on the AstBuilder migration: the legacy methods are marked `#[deprecated]` in this cycle, but downstream crates that build custom ASTs on top of Oxc will hit warnings now and breakage in the next cycle. The PR cluster around #23877 is the spot to monitor; if a downstream crate (rolldown, biome, vite's Rolldown port, parcel) opens an issue about the new `AstBuilder` shape, expect a v0.139 cycle with an explicit migration guide. Second, watch for oxfmt v0.58 to ship a graphql-or-css compat parity entry. The prettier-diff parity PRs (#23327, #23419) closed the gap substantially, but the release notes flag real-world diffs as still expected; a v0.58 entry that brings the diff count down to zero on a representative CSS / GraphQL codebase would confirm the new formatters are production-ready for migration. Third, watch for `value_type` memoization to land in `oxc_isolated_declarations` or `oxc_transformer`. The PR #23929 design is explicit that the cache is opt-in via hooks on `GlobalContext`, and only the minifier supplies a real cache in this cycle. The next cycle is the natural place for the transformer and isolated-declarations to opt in; if they do, type-stripping pipelines will get the same arithmetic-chain perf gain the minifier just got.

The broader lesson is the one the [Prettier 3.9 article](/articles/2026-06-28--prettier-3-9-micromark-yaml-graphql-rust-flow-parser) made two days ago: the JavaScript toolchain is being rebuilt on top of the Rust Oxc stack, one grammar at a time, and the v0.138 cycle closes two more grammars (CSS / LESS / SCSS and GraphQL on the oxfmt side) and finishes an internal API migration (AstBuilder + GetAllocator on the crates side). The same pattern shows up at [Cline's SDK migration](/articles/2026-06-27--cline-4-0-sdk-rewrite-clinepass-customize-marketplace-plugins), at [Vite's Vite+ unification](https://voidzero.dev/posts/announcing-vite-plus-alpha) (the banner ad on the Oxc website), and at the [Bun + Anthropic integration](/articles/2026-04-19--bun-joins-anthropic-ai-coding-infrastructure). The shape of 2026 across the Oxc ecosystem is a sequence of large architecture rewrites shipped in stages, with each cycle marking one more component as 'done' and freeing the next cycle to focus on the remaining gaps.