char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
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:
{
"compilerOptions" : {
"jsx" : "react-jsx" ,
"jsxImportSource" : "preact"
}
}
Supported JSX options:
| Option | Meaning |
|---|---|
jsx: "react-jsx" | Automatic production transform; imports from <source>/jsx-runtime. |
jsx: "react-jsxdev" | Automatic development transform; imports from <source>/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:
/** @jsxRuntime classic @jsx h @jsxFrag Fragment */ import { h , Fragment } from "./ui.ts" ; export const view = <>< p > Hello </ p ></>;
@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 for remaining
checking limitations.
1# JSX and TSX 2 3avril uses Oxc to transform `.jsx` and `.tsx` modules into ES modules before 4execution. TypeScript types are erased, not checked. JSX-generated imports 5participate in normal graph preparation, capability checks, lockfiles, caching, 6and vendoring. Stack traces retain original source locations. 7 8JSX works in entry modules, imports (including dynamic imports), workers, and 9tests. Test discovery includes `*_test.tsx`, `*.test.tsx`, and `test.tsx`. 10Plain `.js` and `.ts` files do not opt into JSX parsing. REPL input remains 11JavaScript, but it can import JSX/TSX modules. 12 13## Compiler options 14 15The default is the automatic production transform: `jsx: "react-jsx"`, with 16`react` as the import source. avril does not provide React or install a JSX 17runtime automatically. 18 19Override the transform in `tsconfig.json`, or set package-wide defaults with 20the same keys in `compilerOptions` in `avril.conf`. The nearest `tsconfig.json` 21overrides the `avril.conf` defaults, and neither applies to other packages. 22The same options apply to `avril run`, `avril bundle`, and the language server. 23These commands all read one effective configuration per module; only the 24four JSX keys below affect the runtime transform, while type checking 25(`avril check` and the language server) additionally honors every other 26`compilerOptions` key the project sets: 27 28``` json 29{ 30"compilerOptions" : { 31"jsx" : "react-jsx" , 32"jsxImportSource" : "preact" 33} 34} 35``` 36 37Supported JSX options: 38 39| Option | Meaning | 40| --- | --- | 41| `jsx: "react-jsx"` | Automatic production transform; imports from `<source>/jsx-runtime`. | 42| `jsx: "react-jsxdev"` | Automatic development transform; imports from `<source>/jsx-dev-runtime` and includes source metadata. | 43| `jsx: "react"` | Classic calls; defaults to `React.createElement` and `React.Fragment`. | 44| `jsxImportSource` | Import source for automatic JSX. | 45| `jsxFactory` | Classic factory identifier or dotted member expression, such as `h` or `UI.createElement`. | 46| `jsxFragmentFactory` | Classic fragment expression, such as `Fragment` or `UI.Fragment`. | 47 48Classic factories must be in scope; avril does not import them automatically. 49`preserve` and `react-native` are accepted by the language server but rejected 50when executing JSX modules: V8 cannot execute preserved JSX. 51 52Only these JSX compiler options affect runtime transformation. TypeScript 53`paths`, `baseUrl`, emit settings, and module-resolution settings do not change 54avril's runtime behavior. 55 56## Runtime imports and pragmas 57 58With `jsxImportSource: "preact"`, resolve `preact/jsx-runtime` (or 59`preact/jsx-dev-runtime`) through your package's `avril.conf` import map. 60Automatic JSX can also import `createElement` from the source itself for 61spread/key cases. Map that specifier too if your code needs it. 62 63The source can instead be a supported HTTP or JSR specifier, such as 64`jsr:@your-scope/ui@1` for a package exporting `./jsx-runtime`. All generated 65imports use the originating module's resolver and execution authority. 66This does not enable npm, CommonJS, or Node compatibility. 67 68Oxc's leading JSX pragmas can override file-level transform settings: 69 70``` tsx 71/** @jsxRuntime classic @jsx h @jsxFrag Fragment */ 72import { h , Fragment } from "./ui.ts" ; 73 74export const view = <>< p > Hello </ p ></>; 75``` 76 77`@jsxImportSource` also selects a per-file automatic import source. Pragmas must 78precede the first statement. 79 80## Configuration ownership and permissions 81 82For local JSX modules, avril looks for the nearest `tsconfig.json`, walking 83from the module's directory up to its owning `avril.conf` directory, inclusive. 84A nested package does not inherit its consumer's configuration. Without an 85owning package, discovery walks trusted ancestors until an authority or trust 86boundary stops it. 87 88Configs are JSONC: comments, trailing commas, and an initial UTF-8 BOM are 89accepted. `extends` supports relative or absolute file paths and arrays of 90those paths. Paths resolve against the declaring config; if an exact file is 91missing, avril also tries appending `.json`. Later bases override earlier 92bases, and the current config overrides its bases. Cycles and oversized graphs 93are rejected. Package-name and URL-based `extends` are not supported yet. 94 95Like package metadata, config discovery requires `js-exec` authority, not a 96guest `read` grant. Denied discovery stops without probing whether a config 97exists. Explicitly extended configs must also be authorized. Configs must be 98trusted, regular, non-symlink files; world-writable config authorities are not 99trusted on Unix. Under `-0`, grant execution authority for the project if its 100configs and imported JSX runtime should be available, for example 101`--allow-js-exec=.`. 102 103Newly prepared modules read their configuration under current authority; 104already-prepared modules retain their compiled code. Remote HTTP/JSR modules 105never inherit local tsconfig settings and do not fetch remote tsconfigs 106implicitly. They use defaults or their own leading pragmas. 107 108## Language server 109 110`avril lsp` uses the same configuration loader and Oxc transform to discover 111implicit runtime imports alongside written type dependencies. Runtime imports 112follow the existing declaration-redirection rules. 113 114The language server tracks each source's effective compiler options — the 115TypeScript backend's defaults, overridden by `avril.conf`, overridden by the 116nearest `tsconfig.json` — and reports configuration errors without rewriting 117user configs. Separate checking contexts support different settings across 118packages; see [the LSP documentation](../lib/lsp/README.md) for remaining 119checking limitations.