Skip to content

Command line

Generated from docs/site/scripts/cli.mjs when the site was built at 7aa23e2.

Each section is the comment at the top of the tool’s source, as it is in the repository when the site is built.

Runs scripts or a page against a headless DOM on QuickJS. From crates/niso-quickjs/src/bin/niso-run.rs.

niso-run: runs scripts or a web page against a headless niso DOM.
niso-run [--html FILE | --page FILE [--root DIR] [--url URL]] [--serve URL=FILE]... [--dump]
[--boxes] [--missing] [--max-ms N] [--tap X,Y]... [--repeat N] [--render FILE] [--time]
[--hold] [--storage DIR] SCRIPT...
--html sets document.body's content first. --page loads an HTML page the
way a browser does: its stylesheets, classic and module scripts and the
modules they import come from the filesystem or data: URLs, and the given
scripts run once it is parsed, before its load event. With --root the
page is at http://localhost/ plus its path under DIR, and that origin's
URLs are files under DIR; otherwise it is a file: URL. --url gives the
page another URL, such as the route a single-page app serves the file at.
--serve answers GETs of URL (fetches and the document's resources) with
FILE's bytes, so a page that reads the network sees the same answer on
every run.
--storage keeps localStorage and IndexedDB in DIR, where a later run with
the same DIR finds them, as a reload would; without it they go in a
directory of the run's own that it removes at the end.
--missing lists every DOM interface member and global that script looked
up and niso does not have. With --tap, --render or --time, a frame is
rendered after the scripts and their timers finish, the way a host
renders one (due tasks run, then the render stream), and another after
each --tap at X,Y CSS pixels; --repeat makes the taps N times. --dump then
prints the document's HTML; --boxes prints every element's border box
under body as JSON, in the form tests/screens/probe.js gives. --render
writes every frame's render stream to FILE, each as its length (u32,
little-endian) and bytes. --time prints the time from start to the first
frame (split into creating the DOM and engine, the scripts with their
timers, and the frame), the mean time per tap frame, the nodes alive
after a full GC, and the process's peak resident set size to stderr. --hold
then keeps the process, its workers included, alive until stdin closes,
so a heap tool (heap, vmmap, malloc_history) can inspect it. Exits 1 on
any uncaught exception or any script that could not be read.

The same, on Node (or Deno, Bun) through the Node-API addon. From bindings/js/napi/niso-node.js.

niso-node: niso-run on Node-API, running scripts or a web page against a
headless niso DOM in a V8 realm (or JavaScriptCore's, under Bun).
niso-node [--html FILE | --page FILE [--root DIR] [--url URL]] [--dump] [--boxes]
[--max-ms N] [--tap X,Y]... [--repeat N] [--render FILE] [--time] [--storage DIR] [--live] SCRIPT...
niso-node --wpt
The options are niso-run's (crates/niso-quickjs/src/bin/niso-run.rs), on
virtual time unless --live, which runs the page in real time from Node's
event loop until it has nothing left to do. --wpt runs a test page that
niso-wpt --engine node describes as JSON on stdin. Module scripts need
vm.SourceTextModule, which node --experimental-vm-modules has: run as
node --experimental-vm-modules niso-node.js, or as the file itself.

Runs a script compiled ahead of time by Porffor. From crates/niso-porffor/src/bin/niso-run-porffor.rs.

niso-run on Porffor: the same runner, built with the scripts it runs.
NISO_PORFFOR_SCRIPTS=app.js cargo build --release -p niso-porffor
target/release/niso-run-porffor [--dump] ... app.js

The web-platform-tests runner. From crates/niso-wpt/src/main.rs.

niso-wpt: runs web-platform-tests testharness.js tests against niso.
niso-wpt [--update] [--filter TEXT] [--jobs N] [--features ID,...] [DIR...]
Runs WPT's testharness.js tests, each in its own process, and compares
the results with this system's expectations: tests/wpt/expectations.json
and the subtests tests/wpt/expectations.<os>.json says differ here.
A file whose results differ runs twice more, and a subtest's result
only changes when all three runs agree. Exits 1 when a subtest that
passed before fails now, or a file reports a different number of
subtests, unless tests/wpt/flaky.txt lists its file as
nondeterministic. --update records the results instead (all of them
on a full run, so tests that left the suite drop out), except for
the files flaky.txt lists, whose expectations stay as they are.
The tests are the given test files and those under the given WPT
directories, or those WPT maps
to the given web-features (--features), or by default the Baseline
suite: every test WPT maps to a Baseline feature (widely or newly
available) that tests/wpt/excluded-features.txt doesn't exclude, and
every test under the directories in tests/wpt/suites.txt.
Tests that use testdriver.js run with niso-wpt's own testdriver
(VENDOR): clicks, typing and WebDriver action sequences become niso's
input calls (niso-actions), and its other calls fail.
The results go to target/wpt/results.json, and a full run (no
directories, features or filter) scores them against the Baseline
features in tests/wpt/baseline.json (tests/wpt/baseline.mjs).
niso-wpt --engine node [--filter TEXT] [--jobs N] [--features ID,...] [DIR...]
Runs the same tests, chosen the same way, once each on the Node-API
binding (V8 under node, with the addon built next to niso-wpt or
named by NISO_NAPI; NISO_RUNTIME names another runtime: a node, deno
or bun binary). It writes only under target/wpt-napi/: results.json in
the expectations' form, diff.md with how each file's results differ
from this system's (QuickJS's) expectations, and on a full run its
Baseline score, baseline.json. The expectations, flaky.txt and
tests/wpt/baseline.json are QuickJS's, and it never changes them.
niso-wpt --one FILE
Runs one test file (a path in third_party/wpt, or an absolute one)
and prints its results as JSON, against a wptserve of its own unless
NISO_WPT_SERVER names a running one's address, as a run's child gets.
niso-wpt --suite test262 [--update] [--engine node] [--filter TEXT] [--jobs N] [DIR...]
Runs test262's intl402 tests the same way, each file once in each mode
it runs in (test262.rs), against tests/test262's expectations, and
scores the Intl features in the Baseline score.
The WPT checkout lives in third_party/wpt (tests/wpt/fetch.sh), test262's
in third_party/test262 (tests/test262/fetch.sh).

The desktop host. From hosts/iced/src/main.rs.

niso-iced: the Linux host. It runs a page script in a niso DOM with
QuickJS and renders the page with iced, from the render stream as the iOS
and Android hosts do.
niso-iced SCRIPT.js [--size WxH] [--scale S] [--tap X,Y]...
niso-iced --page FILE [--root DIR] [--url URL] [--max-ms N] [--size WxH] ...
--page loads an HTML page as niso-run --page does: with --root, the
page's origin http://localhost/ serves files under DIR, and --url gives
the page another URL. Its scripts and their timers run for up to --max-ms
(60000) of page time before the first frame.
Taps given with --tap run half a second apart after launch, so tests can
drive the page. The screenshot harness (tests/screens/compare.mjs) adds
--screenshot OUT.png, which renders the page offscreen at --size and
--scale after the taps instead of opening a window, --probe OUT.json,
which writes probe.js's element boxes, and the iOS host's switches:
--no-text, --no-controls, --hide-scrollbars, and --native-controls and
--native-fields with base64 JSON.

Generates a native module’s bindings from its IDL. From crates/niso-idl/src/bin/niso-module.rs.

Generates a native module's code from its WebIDL file (see niso_runtime.h):
niso-module js FILE the page's import, niso:<name>
niso-module dts FILE its TypeScript declarations
niso-module java FILE PACKAGE DIR the JVM classes, into DIR

Builds and runs the SwiftUI host. From hosts/apple/build.sh.

Builds the SwiftUI host for one Apple platform with a page, and runs it.
hosts/apple/build.sh [--platform P] [EXAMPLE | --page DIR | --page FILE [--root DIR] | --app LIB]
[--name NAME] [--bundle-id ID] [--icon PNG] [--out DIR]
[--debug] [--no-launch] [[--] APP ARGS...]
Options come in any order; the first argument that is none of them starts
the app's arguments (or the one after --).
P is ios-sim (the default), ios, macos, tvos-sim, tvos, visionos-sim,
visionos, watchos-sim or watchos. EXAMPLE names a directory in examples/
(default: counter), built as a JS bundle. --page runs an HTML page instead:
DIR is copied into the app's resources as its root, served at the app's
origin https://<bundle id>.app.niso/, and its index.html loads from it; a
FILE is copied alone, or with --root DIR, DIR is the root and FILE in it
loads. --app runs the app in LIB instead, a static library for the
platform exporting niso_app_main (see niso_app.h). --debug compiles the
host with DEBUG, which takes -niso-page FILE -niso-root DIR at launch.
The app is NAME.app (default Niso.app) in --out, by default target/ios for
ios-sim and target/apple/P for the rest, ad-hoc signed. A macOS app gets
PNG as its icon. On iOS it carries its widget extension (home screen
widgets and the Live Activity) in PlugIns/NisoWidgets.appex. APP ARGS go to
the app, like -niso-tap X,Y to tap at a point after launch.
Launching: macOS opens the app; a simulator platform installs and launches
it on NISO_SIMULATOR (a UDID or a device name, see simulator.sh), booting
it if needed; device platforms only build. --no-launch only builds: it
touches no simulator.
niso-app is built with cargo for the platform's target, unless NISO_LIBDIR
names a directory with its libniso_app.a and an include/ of its headers
(niso.h, niso_runtime.h, niso_js.h). The Rust targets are rustup's
aarch64-apple-{darwin,ios,ios-sim,tvos,tvos-sim,visionos,visionos-sim,
watchos,watchos-sim}; a missing one is added. NISO_ENGINE=porffor runs the example
on Porffor instead of QuickJS: its script (and probe.js) compiled into the
app ahead of time, with porf from PORF or PATH (see docs/engines/porffor.md).

Builds and runs the Compose host. From hosts/android/build.sh.

Builds the Android host with one example page, installs it on a running
emulator or device (starting the AVD in NISO_AVD, default quilt, if none is
attached) and launches it.
hosts/android/build.sh [EXAMPLE | --app LIB | --jvm DIR CLASS] [--no-launch | AM START EXTRAS...]
EXAMPLE names a directory in examples/ (default: counter). --app runs the
app in LIB instead, an arm64 shared library exporting niso_app_main and
linked against libniso_android.so (see niso_app.h). --jvm builds the Java
sources in DIR into the app and runs CLASS, a Consumer<dev.niso.dom.Dom>
with a public no-argument constructor that builds its page in accept
(examples/lang/java Timer, say). Extras go to the
app: --es niso.taps "X,Y;X,Y" taps after launch, --ez niso.probe true writes
files/probe.json, --ez niso.notext true draws boxes only. With NISO_APK_LABEL
set it only builds a standalone APK of the example instead (see apk.sh).
NISO_ENGINE=porffor runs the example on Porffor instead of QuickJS: its
script (and probe.js) compiled into the native library ahead of time, with
porf from PORF or PATH (see docs/engines/porffor.md).

Builds and runs the iced host. From hosts/iced/build.sh.

Builds the iced host and the example pages, and runs one example in a window.
hosts/iced/build.sh [EXAMPLE] [--no-launch | APP ARGS...]
EXAMPLE names a directory in examples/ (default: counter). APP ARGS go to the
app, like --tap X,Y to tap at a point after launch or --size WxH. The app is
left in target/release/niso-iced.

Builds the example pages. From examples/build.mjs.

Builds each example (a directory with a main.js, or with pages/*.js for an
app of several pages) into dist/<name>.js (dist/<name>-<page>.js), the
script a native host runs, and dist/<name>.html, the same page for a
browser to render as reference.

Runs every check. From tests/check.sh.

Runs niso's checks.
tests/check.sh the crate layering lint (cargo xtask layers),
Rust and C tests, the timer app in each language
under examples/lang (needs Go, Zig 0.17 and a
JDK in JAVA_HOME), ihatemyphone's pages, the
headless Svelte fixture, WPT, test262's intl402,
and the Acid tests (layout against Chrome)
tests/check.sh --ios also renders tests/screens/cases.txt on the iOS
Simulator and compares each with Chrome, and
checks text against the platform's text styles
(tests/screens/text.mjs) and radio's CarPlay
list (tests/carplay/check.sh)
tests/check.sh --android the same on the Android emulator
tests/check.sh --mac also plays a Mac's input into the macOS host
(tests/mac-input/check.sh, which skips without
a logged-in session)
tests/check.sh --devices both
tests/check.sh --iced the same on the Linux iced host, offscreen
tests/check.sh --docs-slow also runs the docs' slow runnable blocks
(device builds; docs/CONTRIBUTING-docs.md)
NISO_SKIP_DOCS=1 tests/check.sh
everything but the docs check, for a machine
without the site's packages (see below)
The docs check (docs/site/check.sh) needs the site's packages installed
once: (cd docs/site && pnpm install --frozen-lockfile). Without them the
check fails with that instruction, unless NISO_SKIP_DOCS=1 skips it.
Device runs leave side-by-side screenshots and reports in target/screens/.

Runs an app of the corpus headless. From tests/apps/run.sh.

Runs an app of the corpus (docs/compat/apps.md) headless with its driver.
tests/apps/run.sh NAME --fetch
tests/apps/run.sh NAME [--engine quickjs|node|bun] [--screenshot]
NAME is a directory under tests/apps, or APP-VARIANT for an app built in
several variants (todomvc-svelte runs tests/apps/todomvc with svelte).
--fetch fetches and builds the app with its fetch.sh, pinned to an exact
upstream commit or version, into $NISO_APPS/NAME (target/apps by default):
its static serve root is root/ there. It is the only step that needs the
network. It writes a stamp, the hash of the app's fetch.sh, the files it
builds from (host/, make-index.mjs: pins and lockfiles) and the variant, and
a run whose build is missing or has another stamp, as after a pin is
bumped, stops and says to fetch again. Each run serves root/ at
http://localhost/ and loads its index.html with the app's driver.js added
as the last module script; the driver performs the app's core flow and
prints NISO-APP lines, which this prints. A driver that prints
"NISO-APP reload" is run again, as a reload: a second process with the same
storage directory, where NISO_APP_RUN is 2. Logs are NAME/ENGINE-runN.log,
and each run's page NAME/root/niso-app-ENGINE-N.html, so runs on different
engines can share a build at the same time.
--screenshot also renders the page with niso-iced into NAME/ENGINE.png:
on QuickJS niso-iced runs the page and its driver itself; on Node and Bun,
which niso-iced does not run, it renders the DOM the first run ended with
(its scripts removed, so canvases are blank). niso-iced has a storage
directory of its own, emptied first (NISO_STORAGE_DIR).
NISO_PROFILE=debug runs debug builds instead of release ones, and
NISO_BUILD=0 runs the binaries already built without building them.
An app's optional app.conf sets max_ms (page time each run gets) and size
(the screenshot's, WxH). Exits 1 when a driver line says FAIL or the driver
never says done.

Repository tasks: the layer lint, header sections, the docs headers. From xtask/src/main.rs.

Repository checks that are not tests of one crate.
cargo xtask layers the crate layering rules of
docs/architecture/architecture.md, section 2.1
cargo xtask split cuts niso_runtime.h and glue.js into the sections
crates/niso-compose/sections.txt gives each crate,
writes them to target/fragments, and checks that
the composed files have the monoliths' lines;
--cut-over makes the sections the source (6b,
done: on main it fails, as the monoliths are gone)
cargo xtask resplit in a merge of the cut-over: moves a branch's edits
of the monoliths into the sections' files
cargo xtask docs [DIR] writes the composed niso.h and niso_runtime.h and
sections.json (each section of the header and the
JS glue with its owner crate and source file) to
DIR, target/docs by default, for the docs site's
C API reference (docs/site/scripts/generate.mjs)

The docs check. From docs/site/check.sh.

The docs check (docs/CONTRIBUTING-docs.md), which tests/check.sh runs: it
generates the reference and the included pages, builds the site (which
fails on a broken internal link or a reference to code that's gone), and
runs scripts/check.mjs (stamps, references in prose, numbers, screenshots,
runnable blocks; drift is reported, not failed).
docs/site/check.sh [--slow] [--no-run] [--page PATH]
It runs offline once the site's packages are installed: run
`pnpm install --frozen-lockfile` in docs/site once.