Code coverage for AssemblyScript projects using a compiler transform, a tiny AssemblyScript helper module, and Node.js report glue.
For the standard setup, install the convenience package plus the AssemblyScript tools used by your test runner:
npm install --save-dev @as-covers/core assemblyscript @assemblyscript/loader@as-covers/core depends on @as-covers/assembly, @as-covers/transform, and @as-covers/glue, and re-exports the glue API.
Add your normal AssemblyScript entry file, the as-covers helper declarations, and the transform to the asc command:
npx asc ./assembly/index.ts \
--lib ./node_modules/@as-covers/assembly/index.ts \
--transform ./node_modules/@as-covers/transform/lib/index.js \
--outFile ./build/coverage.wasm \
--exportStart _startReplace ./assembly/index.ts with your test entry file. The --lib path makes the injected __cover imports type-check, and the --transform path points at the packaged transform output.
Covers reads declared source-file strings through the @assemblyscript/loader string helpers, so instantiate the instrumented wasm with @assemblyscript/loader or provide equivalent exports.__getString support in a custom loader.
To skip instrumentation for an intentional line, place // @as-covers: ignore on the line immediately before it.
The ignore applies only to the next line in that same source file.
import fs from "node:fs";
import loader from "@assemblyscript/loader";
import { Covers } from "@as-covers/core";
const covers = new Covers();
const wasmModule = loader.instantiateSync(
fs.readFileSync("./build/coverage.wasm"),
covers.installImports({})
);
covers.registerLoader(wasmModule);
wasmModule.exports._start();
process.stdout.write(covers.stringify());
fs.writeFileSync("./build/lcov.info", covers.toLCOV());
fs.writeFileSync("./build/coverage.html", covers.toHTML());toLCOV() writes each cover point as line data and emits function points as synthetic LCOV function records using the cover point id. toHTML() writes a dependency-free static summary table.
Use covers.diagnostics() to inspect non-fatal registry issues such as id collisions or cover(id) calls that ran before a declaration. Pass new Covers({ strict: true }) to throw on unknown cover(id) events instead of recording only a diagnostic.
Use covers.resetCoverage() between repeated runs when you want to keep declarations and clear only hit state. covers.clearDeclarations() clears declarations and diagnostics; covers.reset() remains a backward-compatible alias for clearing declarations.
Declarations and hit state accumulate across repeated _start() calls and across multiple instrumented binaries that share one Covers instance. Call registerLoader() with the loader for the binary you are about to start so source-file pointers decode against the right module. Exact duplicate declarations are idempotent; mismatched duplicate ids are kept as diagnostics.
The repository package smoke test packs the packages, installs them into a throwaway consumer, compiles tests/test.ts with these package paths, and runs this loader flow:
npm run test:packageMIT. See LICENSE.