Coverage Reports
scriptc coverage answers "how much of my program compiles to native code?" It analyzes the program without building it and assigns every statement to a tier. No global scoreboard, no hand-waving: the numbers are for your program, and every non-static site is named with an error code.
A fully static program
$ scriptc coverage app.ts
statements analyzed 10
compile statically 10 (100%)
fully static — this program has no dynamic remainder.This is the common case for typed application code: the whole program becomes native code, and a scriptc build binary carries no engine.
A program with a dynamic remainder
Import an npm package and the report changes shape:
$ scriptc coverage cli.ts
statements analyzed 4
compile statically 3 (75%)
runs with --dynamic 2 sites (embeds a JS engine, ~620KB — static stays the default)
×1 importing 'picocolors' requires the embedded dynamic engine, which this build does not include — the package's implementation runs there SC2013
×1 values from the 'picocolors' package run in the embedded dynamic engine, which this build does not include SC2013Reading it line by line:
| Line | Meaning |
|---|---|
statements analyzed | Every executable statement in your program (not in dependencies). |
compile statically | Statements that become native code — no engine involved. |
runs with --dynamic | Sites that would run in the embedded engine if you rebuilt with --dynamic. Without the flag, each is a compile error — this build does not include an engine, and never will silently. |
blockers | Statements that compile in no tier yet, each with a count, a one-line reason, and its SC code. These are the rejected tier: rebuilding with --dynamic does not make them go away. |
The --dynamic view
scriptc coverage --dynamic answers a different question: what would a --dynamic build compile, and what still blocks it?
$ scriptc coverage cli.ts --dynamic
statements analyzed 4
compile statically 3 (75%)
compile dynamically 1 (25%) (island sites — the embedded engine runs them)
builds with --dynamic — no remaining blockers (the island sites above run in the embedded engine).The closing line is the actionable verdict: this program builds with --dynamic. When it doesn't, the remaining blockers are listed exactly like the static view's.
The embedded-builtins report
When embedded npm code imports Node builtin modules, the --dynamic report says so — each builtin the embedded dependency graph reaches, whether it's shimmed inside the engine, and which package wanted it:
$ scriptc coverage tool.ts --dynamic
statements analyzed 5
compile statically 2 (40%)
compile dynamically 3 (60%) (island sites — the embedded engine runs them)
embedded npm code imports Node builtins:
node:child_process shimmed (commander)
node:events shimmed (commander)
node:fs shimmed (commander)
node:path shimmed (commander)
node:process shimmed (commander)
node:util shimmed (commander)
builds with --dynamic — no remaining blockers (the island sites above run in the embedded engine).The shims are reimplementations inside the engine, not Node itself — see npm Dependencies for what that means.
What the fences mean
Blocker lines carry SC codes — the same codes scriptc build errors with, so the coverage report and the compiler never disagree. A few common shapes:
'X' is part of the standard library types but has no scriptc lowering yet (SC2020)— the type checker sees the full standard library, but only the supported surface compiles. The build error at that site includes the supported-alternatives hint.importing 'pkg' requires the embedded dynamic engine (SC2013)— npm package implementations run in the engine; add--dynamicor drop the dependency.'Response.arrayBuffer() in a static build' is typed but has no scriptc lowering yet (SC2020)—fetchitself is native static; useResponse.bytes()for a byte body, or--dynamicfor the wider Web API.passing 'unknown' values where 'any' is expected (SC1100)— theany/unknownboundary rules; narrow or cast first.
Type errors gate the analysis
Coverage only analyzes programs that typecheck. A program with TypeScript errors reports them instead of numbers:
$ scriptc coverage broken.ts
not analyzable: 1 TypeScript error — fix type errors first (scriptc only analyzes programs that typecheck)This is deliberate: tier assignment is driven by types, so numbers computed over an ill-typed program would be fiction.
External host type surfaces
Some applications run inside an embedder that provides modules which do not
exist in node_modules. When the embedder ships a declaration restating that
surface, map its exact bare specifier during coverage:
scriptc coverage src/core.ts --external-types @native-sdk/core=types/native-sdk-core.d.ts
The option is repeatable. Relative declaration paths resolve from the current
working directory; .d.ts, .d.mts, and .d.cts files are accepted. The
declaration participates in type checking, so project-owned modules and local
values using its structural types can be measured. Type-only imports add no
runtime boundary. Relative declaration imports and re-exports are included, so
the mapped file may be a conventional index.d.ts barrel.
This mapping deliberately does not claim that the host module can execute in a
scriptc binary. Value imports and uses appear as SC1010 external-host
blockers, while coverage continues counting the rest of the application. The
option is available only on scriptc coverage; builds still require an actual
module implementation or an explicit runtime integration.