nyc (the Istanbul CLI, v18) cannot load a .ts file at all — it hijacks Node’s .ts extension handler and compiles TypeScript as raw JavaScript, throwing SyntaxError: Unexpected token ':'. Discovered during FKITDEV-8387; it means vuer_oss/supervisor_vuer_oss_e2e_test.conf has been broken since FKITDEV-8246 “TS Magic” landed in January 2026.
Gotcha
npx nyc node <anything-that-requires-a-.ts-module>crashes at the first.tsrequire.nyc’s coverage require-hook (append-transform→default-require-extensions/js.js) replaces the.tsextension compiler with the JavaScript compiler, so type annotations reach V8 as JS syntax and blow up. Node’s own runtime type-stripping is bypassed because nyc’s hook wins.
Symptoms
SyntaxError: Unexpected token ':'
at Module.replacementCompile (node_modules/append-transform/index.js:60:13)
at module.exports (node_modules/default-require-extensions/js.js:7:9)
The Unexpected token ':' is a type annotation (foo: string) being parsed as JavaScript.
Root cause
nyc installs a require hook to instrument every loaded module for coverage. It does this by wrapping the extension handlers in require.extensions. For .ts it routes through default-require-extensions’ .js compiler (js.js) via append-transform — i.e. it treats .ts source as JavaScript before instrumenting. Node ≥ 22.18 would normally strip the types (see typescript-in-vuer-repos), but nyc’s hook replaces that handler, so the raw TS text is compiled as JS.
Neither --extension=.ts nor --include '**/*.ts' helps — those flags only widen which files nyc instruments, they do not teach nyc’s compiler about TypeScript syntax.
Consequence: the e2e supervisor conf is dead
vuer_oss/supervisor_vuer_oss_e2e_test.conf wraps every one of the 7 entrypoints as npx nyc node <file>.js. And server.js already requires six .ts services at boot:
server.js:48, 83, 99, 108, 109, 110
So the very first .ts require under nyc throws. The conf has been broken since TS Magic landed (Jan 2026). Nothing outside the git index references the file — no CI job invokes it, no Docker / deploy repo copies it — which is why the breakage went unnoticed.
Fix (own ticket)
Two options, both simple:
- Swap
nycforc8.c8uses V8’s built-in coverage (NODE_V8_COVERAGE) and installs norequirehook, so Node’s native type-stripping runs untouched and.tsloads normally. Drop-in for thenpx nyc node <file>invocation. - Retire the conf if e2e coverage collection is no longer wanted.
This is unrelated to the FKITDEV-8387 entrypoint work and warrants its own YouTrack ticket.
For Agents
For coverage over a codebase that loads
.tson plain Node with no build step (see typescript-in-vuer-repos), reach forc8, notnyc. Anynyc-based coverage in these repos is suspect the moment a.tsrequire is on the load path.
Related
- FKITDEV-8387 — where this was found (entrypoint TypeScript migration)
- FKITDEV-8246 — “TS Magic”, the change that introduced the
.tsboot requires - typescript-in-vuer-repos — how
.tsruns with no build step (the mechanism nyc breaks) - entrypoint-rename-blast-radius — the e2e conf is one of the 7 in-repo supervisor confs
- vuer_oss