Skip to main content

Scripts

Yeet scripts run inside a V8 isolate with a curated set of globals: the yeet object, the terminal, timers, console, TextEncoder, and TextDecoder from the runtime reference, and Worker and SharedWorker for talking to other isolates. The runtime is intentionally minimal — it is not Node.js, not Deno, and not a browser.

Running a script​

yeet run script.js        # run once, exit when done
yeet run -w script.js # watch mode — re-runs automatically when the file changes

Press Ctrl+C to cancel a running script at any time.

See Running scripts for the full yeet run reference, including -p for serving a script's screen or logs over WebSocket and HTTP.

Module system​

Scripts are evaluated as ES modules. import / export syntax works. require() / CommonJS is not supported.

import myQuery from './my-query.graphql';

Special import rules​

File extensionWhat you get
.gql, .graphqlA function (vars?) => { query, subscribe, unsubscribe } — see GraphQL modules
.bpf.oA default-exported BpfObject pointing at that ELF — see eBPF
Everything elseNormal ES module

Subpath imports​

A specifier that starts with # resolves through the imports field of the nearest package.json above the importing module, as in Node. Targets are relative to that package.json.

{
"imports": {
"#/*": "./*",
"#config": "./config.js",
"#lib/*": "./src/lib/*.js"
}
}
import config from '#config';                // ./config.js
import { parse } from '#lib/parse'; // ./src/lib/parse.js
import { foo } from '#/src/lib/bar/baz.js'; // ./src/lib/bar/baz.js

As in Node, a key starts with # and holds at most one *, which matches any text, / included. A target is a ./ path inside the package. yeet does not implement Node's conditions; for compatibility it matches default in a conditions object, as in "#config": { "default": "./config.js" }. Any other entry fails every # import of its package, with an error naming the key and the package.json.

The search for a package.json stops at the project root: for yeet run, the nearest directory at or above the script that holds a package.json or tsconfig.json.

Static import and dynamic import() both accept a # specifier. Worker and SharedWorker throw on one.

import.meta​

PropertyValue
urlfile:// followed by the module's absolute path, or its data: URL
filenameThe module's absolute path
dirnameThe directory that holds it
maintrue only in the script yeet run started. false under yeet test.

A data: URL module has only url and main.

Built-in modules​

ImportContents
yeet:tuiDeclarative terminal UI — Box, Text, Layer, CellBuffer, Disposal, mount, signal, computed, from, effect, face helpers — see TUI
yeet:tui/jsx-runtimeJSX runtime (jsx, jsxs, Fragment)
yeet:tui:layoutLayout engine (Node, Size, layout)
yeet:tui:faceStyled-string and color primitives
yeet:tui:textText measurement utilities
yeet:signalTC39-style signals (Signal.State, Signal.Computed, Signal.subtle)
yeet:workerThe Worker and SharedWorker globals, as an explicit import — see Workers
yeet:messagingMessageChannel, MessagePort, MessageEvent, structuredClone: the port surface workers use — see Ports and channels
yeet:assertassert, assertEquals, assertStrictEquals, AssertionError — see yeet:assert

JSX​

Scripts can use JSX syntax in .jsx and .tsx files. The runtime transpiles it automatically — no pragma or build step required.

import { Box, Text, mount } from 'yeet:tui';

mount(size => (
<Box border="round" padding={1}>
<Text>hello</Text>
</Box>
));

JSX element types must be component functions. String tag names (<div>, etc.) are not supported.

Execution model​

  • Scripts run as ES modules inside a single-threaded V8 isolate.
  • Async/await and promises work — the event loop runs timers and resolves pending promises between turns.
  • The isolate terminates when the top-level module finishes and no pending timers or unresolved promises remain, or when yeet.exit() is called.
  • Uncaught exceptions and unhandled promise rejections are reported to the daemon and terminate the isolate. A worker reports its own errors first, and outlives an unhandled rejection.