Files
Boshen 1c4f519e36 feat(napi): add Relay transform plugin (#25503)
## 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.
2026-08-13 13:56:01 +00:00

115 lines
3.4 KiB
TypeScript

/* auto-generated by NAPI-RS */
/* eslint-disable */
export interface Comment {
type: 'Line' | 'Block'
value: string
start: number
end: number
}
export interface ErrorLabel {
message: string | null
start: number
end: number
}
export interface OxcError {
severity: Severity
message: string
labels: Array<ErrorLabel>
helpMessage: string | null
codeframe: string | null
}
export declare const enum Severity {
Error = 'Error',
Warning = 'Warning',
Advice = 'Advice'
}
export interface SourceMap {
file?: string
mappings: string
names: Array<string>
sourceRoot?: string
sources: Array<string>
sourcesContent?: Array<string>
version: number
x_google_ignoreList?: Array<number>
}
/**
* Apply the Relay `graphql` tagged template transform asynchronously.
*
* This uses a worker-pool thread and can be slower than `transformSync` for a
* single small module.
*/
export declare function transform(filename: string, sourceText: string, options?: TransformOptions | undefined | null): Promise<TransformResult>
/**
* Options for the Relay transform.
*
* `lang`, `sourceType`, and `sourcemap` configure the surrounding Oxc
* parse/codegen pipeline; the remaining fields mirror the options of
* `babel-plugin-relay` / `@swc/plugin-relay`.
*/
export interface TransformOptions {
/** Treat the source as `js`, `jsx`, `ts`, `tsx`, or `dts`. */
lang?: 'js' | 'jsx' | 'ts' | 'tsx' | 'dts'
/** Treat the source as script, module, CommonJS, or infer it from syntax. */
sourceType?: 'script' | 'module' | 'commonjs' | 'unambiguous'
/**
* Generate a source map.
*
* @default false
*/
sourcemap?: boolean
/**
* Directory `relay-compiler` emits all artifacts to (its
* `artifactDirectory` setting). When set, artifacts are imported via a
* relative path from the file being transformed to this directory; the
* path is computed lexically, so both must either be absolute or relative
* to the same base directory. When unset, artifacts are imported from the
* `__generated__` directory next to the file being transformed.
*/
artifactDirectory?: string
/**
* Artifact language, determining the imported file extension:
* `Name.graphql.ts` for `typescript`, `Name.graphql.js` otherwise.
*
* @default 'javascript'
*/
language?: 'typescript' | 'javascript' | 'flow'
/**
* Emit a hoisted default import per `graphql` tag instead of an inline
* `require()` call.
*
* Defaults to `true`, matching `babel-plugin-relay` since Relay v17.
* `@swc/plugin-relay` and Next.js default to `false`.
*
* @default true
*/
eagerEsModules?: boolean
}
/** Result returned by the Relay transform. */
export interface TransformResult {
/**
* Transformed code.
*
* This is empty when parsing, semantic analysis, option validation, or
* the Relay transform reports an error.
*/
code: string
/** Source map, populated when `sourcemap` is `true`. */
map?: SourceMap
/** Parse, semantic, option validation, and Relay transform diagnostics. */
errors: Array<OxcError>
}
/**
* Apply the Relay `graphql` tagged template transform synchronously.
*
* Only `graphql` tags are rewritten; TypeScript and JSX syntax are preserved
* untouched, so the output composes with any downstream toolchain.
*/
export declare function transformSync(filename: string, sourceText: string, options?: TransformOptions | undefined | null): TransformResult