char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somrearrange libs into lib and extensions into extsf4a0f5b

main
5.5 KiB119 linesraw

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:

OptionMeaning
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.
jsxImportSourceImport source for automatic JSX.
jsxFactoryClassic factory identifier or dotted member expression, such as h or UI.createElement.
jsxFragmentFactoryClassic 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.