- Extract "known divergences" section from `AGENTS.md` to explicit `DIVERGENCES.md` with code example
- Update all anchors
- Add missing pinned fixtures
## What
Ports the Relay `graphql` tagged template transform (babel-plugin-relay / swc_relay) as an individual napi transform, per #24914:
- **`crates/oxc_relay`** — the core transform as its own crate (modeled on `oxc_react_compiler`): replaces `graphql` tagged templates with references to relay-compiler artifacts. Definition names are extracted textually like `swc_relay` (equivalent to `\b(fragment|mutation|query|subscription)\s+(\w+)` with `#` comments stripped; hand-rolled scanner, no regex dependency).
- **`napi/transform-relay`** (`oxc-transform-relay`) — standalone napi package copied from the `napi/transform-react` template: parse → semantic → relay traverse → codegen. Only `graphql` tags are rewritten; TypeScript/JSX syntax is preserved untouched, so the output composes with any downstream toolchain.
## Options
| option | default | behavior |
|---|---|---|
| `artifactDirectory` | unset | when set, the import path is computed lexically relative to the transformed file (babel-plugin-relay `getRelativeImportPath` semantics — swc emits absolute paths instead); unset → `./__generated__/` next to the file |
| `language` | `javascript` | `typescript` imports `Name.graphql.ts`, otherwise `Name.graphql.js` |
| `eagerEsModules` | `true` | hoisted default imports (babel-plugin-relay ≥ v17 parity); `false` emits inline `require()` (`@swc/plugin-relay` / Next.js behavior) |
A `graphql` tag with no extractable definition name produces an error diagnostic (babel throws; swc silently skips).
Not supported, documented in both READMEs: dev-mode artifact hash validation, `jsModuleFormat: "haste"`, `isDevVariableName`, swc's Next.js-specific `projects`/`pagesDir`, and GraphQL document validation.
closes#24914
---
Implemented with Claude Code.
Add `oxc-codegen` package - a printer written in TS.
### Features
- Prints JS, JSX, TS, TSX.
- Matches `oxc_codegen` exactly on all Test262, TypeScript, Acorn-JSX fixtures.
- Very fast.
### Deficiencies
- Pretty-printing only (no compact/minified output).
- No support for printing comments.
- Source map support is semi-there, but largely untested, and poor API (design doc has some ideas on how to improve it).
### This PR adds
- The printer code.
- Conformance testing infra.
- Further tests for edge cases.
- README.
- Design doc - how it differs from `oxc_codegen` and why, what produces the perf.
### This PR doesn't add
- Not integrated into CI or release pipeline.
### Notes
This started as a slop port of `oxc_codegen`. I've iterated on that base, cleaned it up a lot, and at least skimmed through all of it. I think it's in fairly decent shape.
The design doc is I think worth a read. It explains the rationale for the choices, in particular the "1 codebase, 4 builds" approach.
I've put it in a new top-level directory called `packages`. It's not an app, so didn't seem to me to fit alongside `apps/oxlint` and `apps/oxfmt`. It's pure JS, so not like e.g. `napi/parser`. And it felt too heavyweight to put into `npm` dir. But maybe there's a better place for it.
Co-authored-by: Cameron <cameron.clark@hey.com>
Closes#19746.
Add `oxlint-plugin-eslint` plugin which exports all ESLint's built-in rules as a JS plugin which can be used with Oxlint.
The code for rules is lazy-loaded on first use, so just using the plugin doesn't load the code for all the rules, only the ones which the user actually uses. However, the `meta` property of each rule is provided eagerly, so that `registerPlugin` in Oxlint can load the plugin without triggering the getters which lazy-load rule code.
All ESLint's rule code is bundled into this plugin package, so the package has no dependencies. This has a few advantages:
1. We control the version of ESLint which the rules are taken from.
2. Avoids "works on my machine" unreproducible bug reports due to differing ESLint versions.
3. Avoids relying on ESLint's `eslint/use-at-your-own-risk` export, which could change without warning.
At present, the plugin contains *all* ESLint's rules, including ones which are natively implemented in Oxlint.
We might choose to scale it back to include only the rules which Oxlint doesn't natively implement. But then we need to consider what happens when we implement more rules in future: Do they disappear from this package without warning? Would that be considered a breaking change? If it would, how long do we keep them in this package?
I propose that in the interests of getting this useful feature released without having to decide all these issues, we just go with it as is for now. JS plugins are not yet stable, so at present we can still make changes later on if we need to, without breaking any promises.
Previously the ESTree tokens serializer had a special case to skip a `<<` token which has same start as preceding `<` token. Instead, solve this problem at source - prevent this duplicate token from being in the `Vec<Token>` in the first place, by modifying the parser.
This is important because we want to move to sending tokens to JS via raw transfer, and we need the `Vec<Token>` to have the right number of tokens in it to start with, so we can do lazy deserialization and just get a token at a specific index. This breaks down if there are extra tokens that need to be skipped.
The logic around this in parser is quite labyrinthine, so add lengthy comments explaining it.
This change also simplifies the main loop in ESTree serializer, so has side effect of +1% on `estree_tokens` benchmark. Conversely, it doesn't affect the `parser_tokens` benchmark perf, because the path in parser which got more complex is not commonly taken.
Alter test fixtures for fixes and suggestions.
Remove trailing newline from end of fixture files, so that the last fix the plugin makes is at very end of file - makes sure fixes in this position still work.
Add checks to these tests and also the BOM test to catch if these fixture files accidentally get formatted, which would add a trailing newline and prevent the tests testing what they should do.
## Summary
- Removes `editors/vscode` directory - code has been moved to
https://github.com/nicholasrice/oxc-vscode
- Removes `tasks/vscode_docs` crate (no longer needed)
- Removes CI and release workflows for VS Code extension
- Updates `editors/README.md` to point to the new repository
- Cleans up references in `.gitignore`, `justfile`, `oxc_release.toml`,
`oxfmtrc.jsonc`, `oxlintrc.json`, and `pnpm-workspace.yaml`
closes#17484🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Alternative to #18796. Part of #18610.
## Overview
Add `@oxlint/plugins` package.
`@oxlint/plugins` package has no dependency on `oxlint`, which solves the problem raised in https://github.com/oxc-project/oxc/pull/18796#discussion_r2751286894, and is also what we wanted in the end anyway. We don't actually want plugins packages to have to depend on `oxlint`.
## Differences from other Oxc packages
This package is different from all our other packages, in that it's intended to work not only with Oxlint's ecosystem, but also with ESLint's ecosystem.
`@oxlint/plugins` will be a *runtime* dependency of plugin packages that the community create, and they may want their plugin to be compatible with both Oxlint and ESLint - this package provides the `eslintCompatPlugin` function for exactly this purpose.
Our aim is to allow plugin authors to migrate from ESLint's `create` API to Oxlint's `createOnce` API with minimum friction, and without breaking changes for their users:
1. Their plugin should remain compatible with ESLint.
2. They do not need to alter the versions of NodeJS they support (no change to `engines` field in `package.json`).
3. They can continue to publish their plugin as a CommonJS package, if that's the format they currently use.
## Package composition
Due to these requirements, the make-up of `@oxlint/plugins` is different from our other packages:
### Dual Format
This package is in "dual package" format, with both ESM and CommonJS entry points.
### Older NodeJS versions support
This package supports NodeJS versions back to v12.22.0.
https://github.com/oxc-project/oxc/blob/9938dc476f8533b7011af03cdbac328b0d00d344/npm/oxlint-plugins/package.json#L40-L42
This matches `engines` field in all ESLint 8.x.x releases:
* 8.0.0: https://www.npmjs.com/package/eslint/v/8.0.0?activeTab=code
* 8.57.1: https://www.npmjs.com/package/eslint/v/8.57.1?activeTab=code
Therefore, `@oxlint/plugins` can be used by any plugin which supports ESLint 8 or later.
Note: Download counts for ESLint 8 are still roughly equal to ESLint 9, even though v9 was released 2 years ago.
#### Notes
* Changing `target` in TSDown to `"node12"` does not result in any changes to built files. See 3rd commit in this PR.
* `exports` field in `package.json` is supported (without experimental flag) from NodeJS v12.17.0 + v14.0.0.
* `.cjs` file extension supported from NodeJS v12.0.0.
## Building the package
This PR adds 2 extra builds to TSDown config, which generate the files for the package. `build.ts` script moves the files into `npm/oxlint-plugins` directory.
Later on, we'll move the logic for moving the files into the CI release workflow, so we don't need to check the generated build files into Git.
## `@oxlint/plugins-dev`
In #18610 we decided to also add an `@oxlint/plugins-dev` to contain `RuleTester`, so we can move that out of `oxlint` package. This PR *does not* add that package. I've skipped that for now as (a) it's trickier and (b) it's much less important.
Restructure the conformance test runner to run the tests from multiple repos, rather than just ESLint.
Key changes:
* Details of each repo are stored in `test-groups.ts`, rather than logic spread across multiple files.
* Runner offers various hooks for mocking modules, mocking `RuleTester` instances, and registering custom parsers.
* Use `tsx` to run conformance tests, to support running tests in TypeScript files which NodeJS cannot run natively.
* Support older versions of ESLint's `RuleTester` where custom parsers were specified in config with file path instead of a parser object.
Closes#12526.
Handle BOM on start of files in the same way that ESLint does - do not include it in the source text on JS side, but `context.sourceCode.hasBOM` evaluates to `true`.
Method:
* Alter `program.source_text` to trim off the BOM before passing AST to JS side.
* Add a `has_bom` flag to `RawTransferMetadata`.
* Add ability to add an offset in the conversion from UTF-8 to UTF-16 spans.
The result is that the file as it's seen on JS side is as if the BOM didn't exist (except for the `hasBOM` flag). Spans are converted accordingly in JS-side AST, and converted back when passing diagnostics back to Rust.
Add conformance tester for JS plugins.
The tester runs all of ESLint's test cases for all its built-in rules, but using Oxlint's `RuleTester` in place of ESLint's. i.e. the ESLint rules are run as Oxlint JS plugins.
It outputs the results in `snapshot.md` file.
Majority of the failing test cases are false positives. Later PRs will improve the conformance tester and `RuleTester` so it correctly handles `sourceType`, `jsx`, and TypeScript sources.
These tests do not run in CI. For now it's just useful for me to commit this, while I work on improving the tester.
I'm not sure if inside `apps/oxlint` is the right place for this ultimately, but for now I think it's passable.
Update `oxfmt` config so it formats `apps/oxlint/test/fixtures`.
Actual formatting changes were in PRs #15600 and #15674. This PR alters the config so all these files will continue to be formatted in future.