---
title: Coverage Reports
url: "https://scriptc.dev/docs/coverage"
docs_index: /llms.txt
lastUpdated: 2026-10-18
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

`scriptc coverage` tells you how much of a program compiles before you build it. Use it when you bring an existing Node.js program to scriptc, add a dependency, or want CI to catch unsupported code early. It analyzes the program without producing an executable, counts the statements that compile, and groups anything unsupported by diagnostic code with a location and a hint.

<span id="static-programs" />

## Run a report

Pass the program's entry file:

```console
$ cat hello.ts
const who: string = process.argv.length > 2 ? process.argv[2] : "world";
console.log(`hello, ${who}`);

$ scriptc coverage hello.ts

  statements analyzed   2
  compile statically    2  (100%)

  fully static — all analyzed statements compile to native code.
```

Every statement in this program compiles, so `scriptc build` will succeed. The counts describe this program only, not JavaScript or Node.js support in general.

<span id="report-fields" />

## Reading the report

When a program has unsupported operations, the report adds a group for each root cause. A group shows the diagnostic code, the reason, the first few sites in source order, and a hint. A generic declaration that fails for several type arguments appears once.

<table>
  <thead>
    <tr><th>Field</th><th>Meaning</th></tr>
  </thead>

  <tbody>
    <tr>
      <td><code>statements analyzed</code></td>

      <td>Executable statements in application code, excluding dependency implementation code.</td>
    </tr>

    <tr>
      <td><code>compile statically</code></td>

      <td>Statements that compile to native instructions.</td>
    </tr>

    <tr>
      <td><code>blockers</code></td>

      <td>Unsupported operations with counts, diagnostic codes, reasons, locations, and hints.</td>
    </tr>

    <tr>
      <td><code>in unreached code</code></td>

      <td>Blockers in code the entry never reaches. A build never compiles that code, so these cannot fail it.</td>
    </tr>

    <tr>
      <td><code>differs from Node</code></td>

      <td>Sites that compile but can behave differently from Node.js. See <a href="#node-divergences">Node divergences</a>.</td>
    </tr>

    <tr>
      <td><code>npm package compilation</code></td>

      <td>Native package compilation outcomes and refusal reasons.</td>
    </tr>
  </tbody>
</table>

Blockers in unreached code and deferred operations in JavaScript packages are listed separately because they don't fail a build. A deferred operation throws a runtime error if it runs, so a successful build doesn't mean every API of a package works; see [unsupported code inside a package](/docs/dependencies#unsupported-code-inside-a-package).

If a function's signature can't compile, the statements in its body count as not compiling, so the percentage reflects how much of the program compiles.

<span id="programs-that-require-dynamic-execution" />

<span id="analyze-with-dynamic" />

<span id="embedded-nodejs-builtins" />

## Diagnostic codes

Coverage and `scriptc build` report the same diagnostic codes. Common ones include:

- `SC2020`: a declared standard-library or Node.js API has no supported compiler implementation.
- `SC2012`: this API form cannot compile natively.
- `SC2013`: a package cannot compile natively; inspect the package-specific reason and the [dependency guide](/docs/dependencies).
- `SC1100`: a value whose type is only known at runtime, such as `unknown`, is used where scriptc needs a specific type. Narrow or cast the value as the diagnostic suggests.

## Node divergences

Some code compiles but can behave differently than under Node.js. Coverage reports the cases it can detect as `SC6xxx` warnings, and `scriptc build` prints the same warnings after a successful build. They never fail a build, but `--fail-on=divergences` can fail a CI job on them.

- `SC6001`: a record passed to, stored as, asserted as, or stored as an array element of a record type with different properties is copied, and the program then writes through the copy or compares it by identity.
- `SC6002`: an object literal's key order differs from its type's declaration order, and the program observes the order through `JSON.stringify`, `Object.keys`, `Object.values`, `Object.entries`, `for...in`, or console output.
- `SC6003`: `localeCompare` compares a string literal outside the built-in Latin-script collation.
- `SC6004`: a call passes a class instance to a function that casts it to an unrelated class.
- `SC6005`: a `Date` string literal uses a form the native parser does not accept.

## Gating builds and CI

By default, `scriptc coverage` exits with status 0 whenever the program type-checks, so you can use the report to track progress. To fail a CI job instead, add `--fail-on`:

```console
$ scriptc coverage src/main.ts --fail-on=blockers
```

`--fail-on=blockers` exits with status 1 when the program has blockers that would fail `scriptc build`. Blockers in unreached code and deferred operations don't count. `--fail-on=divergences` also fails on Node divergences. A program that doesn't type-check always exits with status 1.

Coverage caches its result. Running it again on an unchanged program, or after edits that only touch comments, reuses the previous verdict. Set `SCRIPTC_NO_CACHE=1` to turn the cache off.

## Machine-readable diagnostics

For editors, CI annotations, and other tools, `scriptc coverage --print=diagnostics` and `scriptc build --print=diagnostics` write one JSON document to stdout instead of the human-readable report. The exit status is unchanged. The document looks like this:

```json
{
  "schema": "scriptc-diagnostics",
  "schemaVersion": 1,
  "compilerVersion": "0.3.0",
  "command": "coverage",
  "entry": "/work/app/src/main.ts",
  "success": false,
  "phase": "compile",
  "stats": {
    "statementsTotal": 13,
    "statementsStatic": 12,
    "statementsDynamic": 0,
    "statementsFailed": 1,
    "functionsSkipped": 0,
    "percentStatic": 92
  },
  "groups": [
    {
      "id": "SC1031-c2cc8425",
      "code": "SC1031",
      "category": "unsupported",
      "severity": "error",
      "scope": "reached",
      "message": "object destructuring of non-record values (the source is array-typed)",
      "hint": "...",
      "count": 1,
      "primary": { "file": "/work/app/src/main.ts", "line": 13, "column": 7 },
      "sites": [{ "file": "/work/app/src/main.ts", "line": 13, "column": 7 }]
    }
  ],
  "diagnostics": [
    {
      "code": "SC1031",
      "category": "unsupported",
      "severity": "error",
      "scope": "reached",
      "file": "/work/app/src/main.ts",
      "line": 13,
      "column": 7,
      "endLine": 13,
      "endColumn": 28,
      "start": 352,
      "end": 373,
      "message": "object destructuring of non-record values (the source is array-typed) are not supported yet",
      "hint": "...",
      "group": "SC1031-c2cc8425"
    }
  ]
}
```

<table>
  <thead>
    <tr>
      <th>
        Field
      </th>

      <th>
        Meaning
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        <code>schemaVersion</code>
      </td>

      <td>
        Incremented when a field is renamed or removed or its meaning changes. New optional fields, categories, and codes keep the version.
      </td>
    </tr>

    <tr>
      <td>
        <code>success</code>
      </td>

      <td>
        Coverage: no blockers on the entry path (and, with

        <code>--fail-on=divergences</code>

        , no divergences). Build: an artifact was produced, named by

        <code>artifact</code>

        .
      </td>
    </tr>

    <tr>
      <td>
        <code>phase</code>
      </td>

      <td>
        <code>preflight</code>

        when type checking, configuration, or the module graph stopped the command;

        <code>compile</code>

        when blockers remain;

        <code>native</code>

        when native code generation or linking failed; otherwise

        <code>complete</code>

        .
      </td>
    </tr>

    <tr>
      <td>
        <code>stats</code>
      </td>

      <td>
        Coverage only, absent after a preflight failure: the report's statement counts.

        <code>statementsDynamic</code>

        is always 0 and remains for schema compatibility.
      </td>
    </tr>

    <tr>
      <td>
        <code>category</code>
      </td>

      <td>
        <code>invalid-source</code>

        (the program has a TypeScript or JSON error),

        <code>unsupported</code>

        (valid code scriptc cannot compile yet),

        <code>divergence</code>

        (compiles, but can behave differently from Node.js),

        <code>environment</code>

        (project configuration, scriptc's type world, toolchain, or target), or

        <code>internal</code>

        (a compiler bug).
      </td>
    </tr>

    <tr>
      <td>
        <code>severity</code>
      </td>

      <td>
        <code>error</code>

        , or

        <code>warning</code>

        for divergences.
      </td>
    </tr>

    <tr>
      <td>
        <code>scope</code>
      </td>

      <td>
        <code>preflight</code>

        ,

        <code>reached</code>

        (fails a build),

        <code>unreached</code>

        (code the entry never reaches), or

        <code>deferred</code>

        (a JavaScript statement that compiles to a throw of its diagnostic, which happens only if it executes).
      </td>
    </tr>

    <tr>
      <td>
        <code>line</code>

        ,

        <code>column</code>
      </td>

      <td>
        1-based line and UTF-16 column;

        <code>start</code>

        and

        <code>end</code>

        are 0-based UTF-16 offsets.
      </td>
    </tr>

    <tr>
      <td>
        <code>group</code>
      </td>

      <td>
        The

        <code>id</code>

        of the root-cause group the diagnostic belongs to. A group's

        <code>primary</code>

        site is its first in source order.
      </td>
    </tr>
  </tbody>
</table>

## Type errors

Coverage needs a program that type-checks. If type checking fails, the report lists the type errors instead of statement counts; fix them first.

scriptc type-checks with its own settings: strict null checks, the ES2025 library, and Node.js types (its bundled declarations when the project has no `@types/node`). An error those settings cause, rather than the project's own `tsc` configuration, carries a hint naming the cause, such as a library member newer than ES2025 or a global of another runtime, and machine-readable output reports it in the `environment` category.

## External host type declarations

When your code will run inside a host application that provides its own modules, those modules aren't in `node_modules`. Use `--external-types` to give coverage their declarations so it can analyze the rest of your code:

```console
$ 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. Supported declaration extensions are `.d.ts`, `.d.mts`, and `.d.cts`. Relative declaration imports and re-exports are included, so the mapped file can be an `index.d.ts` barrel. Project-owned code using these types participates in coverage; type-only imports add no runtime boundary.

The mapping supplies types for analysis, not a runtime implementation. Value imports and uses remain `SC1010` external-host blockers while analysis counts the rest of the application. This option is available only for coverage; builds require a module implementation or runtime integration.

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)