Files
scriptc/packages/compiler/src/cli/usage.ts
T
Malte UblandClaude Opus 5.5 1ef31a1b74 Continue a failed checked cast with its value in a dynamic tail
`JSON.parse(text) as T`, `const x: T = anyValue` and `await res.json()
as T` threw `TypeError: expected X at $.path, got Y` when the value did
not fit `T`. Node never checks an assertion and continues with the value
it has, so the build-container listener rejected an order Node accepts
and a JWT with a string `exp` became a 500.

A failed cast now keeps its value when it initializes a `const`/`let`
binding declared in a function or block and only the code after the cast
reads the binding. That code (the statements after the cast in each
enclosing statement list, up to the declaration) lowers twice: the
static copy, unchanged, runs while the value fits; a dynamic copy, in
which the binding and everything derived from it is typed `any`, runs
after a failure, so missing members read undefined, wrong-typed members
keep their values, extra members stay visible in source order, and
objects keep their identity. The cast sets the flag that selects the
copy: the fused JSON.parse helper's slow path and the plain check call
scr_dyn_check_recover, which takes back the TypeError and parks the
value for checkedCast.fallbackTaken/fallbackTake.

A failed value that flows into a typed slot outside the region is
checked there, as any `any` value is: it continues when it fits and
throws at that use when it does not. A statement of the dynamic copy
with no `any` lowering becomes a runtime fence that throws only when a
failed value reaches it. Module-level bindings, regions with hoisted
declarations or super() calls, union targets and targets holding class instances, and
--tier=static-only (and library mode) keep the throwing cast.

`a?.b.c` on an `any` value now short-circuits only on `a`, so `.c`
throws when `a.b` is undefined, as in Node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 15:25:33 -07:00

118 lines
6.8 KiB
TypeScript

export const USAGE = `scriptc — TypeScript/JavaScript to native and WebAssembly executables (experimental)
Usage:
scriptc build <file.ts|.js> [options] compile to an executable or source artifact
scriptc run <file.ts|.js> [options] compile and run
scriptc coverage <file.ts|.js> how much compiles statically, and why not
scriptc coverage <file.ts|.js> --external-types <specifier=file.d.ts>
type-resolve an embedder-provided module for analysis
scriptc build --lib --profile <p.json> library mode: compile the profile's entry
module to a linkable static archive
(<name>.lib.a), or a Wasm reactor
(<name>.wasm) on wasm32-wasi,
exporting the profile symbols; a profile
with a sidecar section also gets the
contract sidecar JSON beside the archive
scriptc cache warm [runtime|tls…] verify and load precompiled runtime families
for the current compiler/SDK/target
Options:
-o, --out <path> primary output path (default: .scriptc/<name><suffix>)
--emit <kind> primary output: ir, llvm, asm, obj, or exe
(default: exe). asm/obj use the matching platform helper
--print <kind> print machine-readable metadata instead of the output path
(native-link-info implies --emit=obj and never links;
diagnostics prints the versioned JSON diagnostics
envelope for build and coverage)
--fail-on <blockers|divergences>
coverage only: exit 1 when the entry path has blockers
(a build would fail), or also when it has Node
divergences
--backend <b> code generator (llvm)
--optimization <release|dev|speed>
native optimization posture (default: release/-O2). dev
uses -O0, source breakpoints, and cached LLVM object shards;
macOS executable builds also produce an adjacent .dSYM.
speed trades larger executables and longer builds for
faster programs (runtime inlining, inline reference
counting, cache-line-aligned runtime code on x86-64)
--strip remove symbol/debug payload from the linked executable
for smaller builds (opt in; --emit=exe only)
--windows-subsystem <console|gui>
Windows executable subsystem (default: console). gui
prevents Windows from opening a console window
--detached-exit
Linux: after process.exit, free the program's memory in
a helper process so the parent sees the exit sooner. The
helper keeps the executable mapped and its memory charged
for up to ~100 ms after exit (opt in; --emit=exe only)
--keep-llvm keep generated LLVM IR beside the executable (default)
--no-keep-llvm delete generated LLVM IR after compiling
--emit-ir also write IR beside an executable or library archive;
deprecated for executables: use --emit=ir for primary IR
--sanitize build with ASan + runtime RC audit
--ffi <file> bind signature-only TypeScript declarations to native
C symbols and link the manifest's archives/libraries
--npm-static <pkg[,pkg…]|auto>
compile the named npm packages' shipped JS statically as
program modules (repeatable; "auto" opts in every eligible
direct import: own .d.ts, unminified JS, no build-transform
markers; "pkg..." also names every package pkg depends
on). Packages that fail preflight are refused with a
diagnostic. Eligible dependencies compile automatically.
--provenance-sources
EXPERIMENTAL: compile npm dependencies from their
provenance-attested SOURCE (fetched at the attested
commit) as static program modules; packages without a
usable attestation use their published source
--external-types <specifier=file.d.ts>
coverage only: map an exact bare module specifier to a
local declaration file. The declaration supplies types
for analysis; the host module remains an explicit
external-boundary blocker (repeatable)
--tier <auto|static-only>
tier policy (default: auto). static-only keeps every
construct without a static lowering a compile error, so
the program has no dynamic-tier demotions, and makes a
checked cast whose value does not fit its type throw
instead of continuing with the value
--explain-dynamic[=<name>]
coverage only: list the functions that operate on dynamic
values and the bindings, fields, functions, classes and
modules the dynamic tier would take over, with the
refusal behind each; a name shows only that unit's chain
--wasm <file.wasm>
coverage only: report a WebAssembly module the program
loads whose path its sources do not spell (repeatable;
modules the sources name, inline modules and packaged
.wasm files are found without it)
-h, --help show this help
-v, --version print the version
`;
export const CLI_OPTIONS = {
out: { type: "string", short: "o" },
emit: { type: "string" },
print: { type: "string" },
"fail-on": { type: "string" },
backend: { type: "string" },
optimization: { type: "string" },
strip: { type: "boolean", default: false },
"windows-subsystem": { type: "string" },
"detached-exit": { type: "boolean", default: false },
"keep-llvm": { type: "boolean", default: true },
"emit-ir": { type: "boolean", default: false },
sanitize: { type: "boolean", default: false },
ffi: { type: "string" },
"npm-static": { type: "string", multiple: true },
"provenance-sources": { type: "boolean", default: false },
"external-types": { type: "string", multiple: true },
tier: { type: "string" },
"explain-dynamic": { type: "string" },
wasm: { type: "string", multiple: true },
lib: { type: "boolean", default: false },
profile: { type: "string" },
help: { type: "boolean", short: "h", default: false },
version: { type: "boolean", short: "v", default: false },
} as const;