# JSX and TSX avril uses Oxc to transform `.jsx` and `.tsx` modules into ES modules before execution. TypeScript types are erased, not checked. JSX-generated imports participate in normal graph preparation, capability checks, lockfiles, caching, and vendoring. Stack traces retain original source locations. JSX works in entry modules, imports (including dynamic imports), workers, and tests. Test discovery includes `*_test.tsx`, `*.test.tsx`, and `test.tsx`. Plain `.js` and `.ts` files do not opt into JSX parsing. REPL input remains JavaScript, but it can import JSX/TSX modules. ## Compiler options The default is the automatic production transform: `jsx: "react-jsx"`, with `react` as the import source. avril does not provide React or install a JSX runtime automatically. Override the transform in `tsconfig.json`, or set package-wide defaults with the same keys in `compilerOptions` in `avril.conf`. The nearest `tsconfig.json` overrides the `avril.conf` defaults, and neither applies to other packages. The same options apply to `avril run`, `avril bundle`, and the language server. These commands all read one effective configuration per module; only the four JSX keys below affect the runtime transform, while type checking (`avril check` and the language server) additionally honors every other `compilerOptions` key the project sets: ```json { "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" } } ``` Supported JSX options: | Option | Meaning | | --- | --- | | `jsx: "react-jsx"` | Automatic production transform; imports from `/jsx-runtime`. | | `jsx: "react-jsxdev"` | Automatic development transform; imports from `/jsx-dev-runtime` and includes source metadata. | | `jsx: "react"` | Classic calls; defaults to `React.createElement` and `React.Fragment`. | | `jsxImportSource` | Import source for automatic JSX. | | `jsxFactory` | Classic factory identifier or dotted member expression, such as `h` or `UI.createElement`. | | `jsxFragmentFactory` | Classic fragment expression, such as `Fragment` or `UI.Fragment`. | Classic factories must be in scope; avril does not import them automatically. `preserve` and `react-native` are accepted by the language server but rejected when executing JSX modules: V8 cannot execute preserved JSX. Only these JSX compiler options affect runtime transformation. TypeScript `paths`, `baseUrl`, emit settings, and module-resolution settings do not change avril's runtime behavior. ## Runtime imports and pragmas With `jsxImportSource: "preact"`, resolve `preact/jsx-runtime` (or `preact/jsx-dev-runtime`) through your package's `avril.conf` import map. Automatic JSX can also import `createElement` from the source itself for spread/key cases. Map that specifier too if your code needs it. The source can instead be a supported HTTP or JSR specifier, such as `jsr:@your-scope/ui@1` for a package exporting `./jsx-runtime`. All generated imports use the originating module's resolver and execution authority. This does not enable npm, CommonJS, or Node compatibility. Oxc's leading JSX pragmas can override file-level transform settings: ```tsx /** @jsxRuntime classic @jsx h @jsxFrag Fragment */ import { h, Fragment } from "./ui.ts"; export const view = <>

Hello

; ``` `@jsxImportSource` also selects a per-file automatic import source. Pragmas must precede the first statement. ## Configuration ownership and permissions For local JSX modules, avril looks for the nearest `tsconfig.json`, walking from the module's directory up to its owning `avril.conf` directory, inclusive. A nested package does not inherit its consumer's configuration. Without an owning package, discovery walks trusted ancestors until an authority or trust boundary stops it. Configs are JSONC: comments, trailing commas, and an initial UTF-8 BOM are accepted. `extends` supports relative or absolute file paths and arrays of those paths. Paths resolve against the declaring config; if an exact file is missing, avril also tries appending `.json`. Later bases override earlier bases, and the current config overrides its bases. Cycles and oversized graphs are rejected. Package-name and URL-based `extends` are not supported yet. Like package metadata, config discovery requires `js-exec` authority, not a guest `read` grant. Denied discovery stops without probing whether a config exists. Explicitly extended configs must also be authorized. Configs must be trusted, regular, non-symlink files; world-writable config authorities are not trusted on Unix. Under `-0`, grant execution authority for the project if its configs and imported JSX runtime should be available, for example `--allow-js-exec=.`. Newly prepared modules read their configuration under current authority; already-prepared modules retain their compiled code. Remote HTTP/JSR modules never inherit local tsconfig settings and do not fetch remote tsconfigs implicitly. They use defaults or their own leading pragmas. ## Language server `avril lsp` uses the same configuration loader and Oxc transform to discover implicit runtime imports alongside written type dependencies. Runtime imports follow the existing declaration-redirection rules. The language server tracks each source's effective compiler options — the TypeScript backend's defaults, overridden by `avril.conf`, overridden by the nearest `tsconfig.json` — and reports configuration errors without rewriting user configs. Separate checking contexts support different settings across packages; see [the LSP documentation](../lib/lsp/README.md) for remaining checking limitations.