char/avril

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

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

Charlotte Somadd progress to module imports from registries7b01146

main
3.5 KiB41 linesraw

JavaScript REPL

Run avril or avril repl to start a persistent JavaScript session. The REPL supports top-level await, multiline syntax, persistent lexical bindings, recoverable syntax/runtime errors, and results formatted by inspect from avril:std, as console.log does; objects can customize this with a Symbol.for("runtime.avril.inspect") method. Results and console output are colored when written to a terminal, unless NO_COLOR is set. Use .help for the built-in commands and .exit (or EOF) to leave. Ctrl-C interrupts an active evaluation; at a terminal prompt it cancels the current line.

Piped input is supported without prompts or banners:

printf 'await Promise.resolve(42)\n' | avril

While evaluating or inspecting a foreground input at a terminal, the REPL reports package downloads and materialization to stderr. It stays quiet while waiting at the prompt.

The REPL uses the same capability defaults as script execution: allow-all unless -0 removes ambient grants. For a restricted session, grant only what it needs:

avril repl -0 --allow-read=./data --allow-js-exec=./scripts --allow-net=example.com:443

Unlike script execution, a -0 REPL has no entry-file grant. --deny-*, registry/cache/lock options, and offline/frozen package settings retain their normal meanings. --include is not used by the REPL; imports entered in the session are prepared on demand.

The REPL never creates or updates a lockfile. Importing JSR, npm, or remote modules resolves against an existing avril.lock where one is present — so its selections and integrity checks, and --frozen, still apply — but new selections are kept only in memory for the session. To record them, run the module with avril run or avril cache instead.

Relative imports resolve from the current working directory. The REPL uses a virtual referrer for resolution; it does not create or load a filesystem entry module and grants no permission to that referrer. Dynamic imports use avril's normal module graph, package resolution, cache, and live capability checks. Built-in avril: modules remain available, while private ext: modules cannot be imported. Both import declarations and dynamic import() are supported; input is JavaScript, not TypeScript. Since the REPL owns standard input, guest reads from avril:std.stdin reject with an explicit “not yet implemented” error.

Import declarations are a REPL convenience, rewritten to await import() with persistent const bindings:

import { inspect } from 'avril:std'
inspect({ answer: 42 })

Default, named, namespace, and side-effect imports are supported. Declarations run in input order rather than being hoisted as in an ES module. Default and named bindings capture exported values at import time; namespace imports retain the module's live properties. Import attributes remain unsupported, just as with dynamic imports.

Background timers and native operations continue to make progress while the REPL waits for input; uncaught background errors are reported without ending the session. EOF and .exit end the session without draining pending background work. With piped input, an await that cannot progress because no host work remains is reported as an error so subsequent input can run. At a terminal, use Ctrl-C to interrupt a pending await; background work is left alone, except that a subprocess blocked in a synchronous wait is stopped so the evaluation can finish. Terminal history is held in memory for the current session.

1# JavaScript REPL
2
3Run `avril` or `avril repl` to start a persistent JavaScript session. The REPL supports top-level `await`, multiline syntax, persistent lexical bindings, recoverable syntax/runtime errors, and results formatted by `inspect` from `avril:std`, as `console.log` does; objects can customize this with a `Symbol.for("runtime.avril.inspect")` method. Results and `console` output are colored when written to a terminal, unless `NO_COLOR` is set. Use `.help` for the built-in commands and `.exit` (or EOF) to leave. Ctrl-C interrupts an active evaluation; at a terminal prompt it cancels the current line.
4
5Piped input is supported without prompts or banners:
6
7```sh
8printf 'await Promise.resolve(42)\n' | avril
9```
10
11While evaluating or inspecting a foreground input at a terminal, the REPL reports
12package downloads and materialization to stderr. It stays quiet while waiting at
13the prompt.
14
15The REPL uses the same capability defaults as script execution: allow-all unless `-0` removes ambient grants. For a restricted session, grant only what it needs:
16
17```sh
18avril repl -0 --allow-read=./data --allow-js-exec=./scripts --allow-net=example.com:443
19```
20
21Unlike script execution, a `-0` REPL has no entry-file grant. `--deny-*`, registry/cache/lock options, and offline/frozen package settings retain their normal meanings. `--include` is not used by the REPL; imports entered in the session are prepared on demand.
22
23The REPL never creates or updates a lockfile. Importing JSR, npm, or remote modules resolves against an existing `avril.lock` where one is present — so its selections and integrity checks, and `--frozen`, still apply — but new selections are kept only in memory for the session. To record them, run the module with `avril run` or `avril cache` instead.
24
25Relative imports resolve from the current working directory. The REPL uses a virtual referrer for resolution; it does not create or load a filesystem entry module and grants no permission to that referrer. Dynamic imports use avril's normal module graph, package resolution, cache, and live capability checks. Built-in `avril:` modules remain available, while private `ext:` modules cannot be imported. Both import declarations and dynamic `import()` are supported; input is JavaScript, not TypeScript. Since the REPL owns standard input, guest reads from `avril:std.stdin` reject with an explicit “not yet implemented” error.
26
27Import declarations are a REPL convenience, rewritten to `await import()` with
28persistent `const` bindings:
29
30```js
31import { inspect } from 'avril:std'
32inspect({ answer: 42 })
33```
34
35Default, named, namespace, and side-effect imports are supported. Declarations
36run in input order rather than being hoisted as in an ES module. Default and
37named bindings capture exported values at import time; namespace imports retain
38the module's live properties. Import attributes remain unsupported, just as with
39dynamic imports.
40
41Background timers and native operations continue to make progress while the REPL waits for input; uncaught background errors are reported without ending the session. EOF and `.exit` end the session without draining pending background work. With piped input, an `await` that cannot progress because no host work remains is reported as an error so subsequent input can run. At a terminal, use Ctrl-C to interrupt a pending `await`; background work is left alone, except that a subprocess blocked in a synchronous wait is stopped so the evaluation can finish. Terminal history is held in memory for the current session.