Skip to content

Instantly share code, notes, and snippets.

Last active Jun 4, 2022
What would you like to do?
IstanbulJS + Babel + TypeScript + ESM workaround

This works around an issue where using Istanbul with the noop instrumenter means it will try to parse your code with a hard-coded Babel config that may not work (especially if the code it's trying to parse is TypeScript).

This kludges the problem away by using patch-package in a post-install script to patch istanbul-lib-instrument to look for an environment variable pointing to your Babel config file, and a one-line patch to nyc to make it pass the filename when calling the patched functions in istanbul-lib-instrment (otherwise it will fail if your babel config includes overrides).

To use this, setup patch-package as shown in their README, then make a patches directory in your repo and drop these two patch files into it. Then just running yarn (or npm install) should be enough to do the patching. Then you just have to make sure that $ISTANBUL_BABEL_CONFIG is set to the path to your babel config file when you run your tests.


yarn add -DW patch-package
jq '.scripts.postinstall = "patch-package"' package.json | sponge package.json
mkdir patches
curl -LO
curl -LO
# (Get the right URLs by right-clicking on the "Raw" buttons for each file below)
cd ..
export ISTANBUL_BABEL_CONFIG="$(realpath -P ./babel.config.js)"
# now you can run your tests or whatever...

Note that the patch files have package version embedded in them, so these patches will only work with those specific versions of the packages they patch.

diff --git a/node_modules/istanbul-lib-instrument/dist/read-coverage.js b/node_modules/istanbul-lib-instrument/dist/read-coverage.js
index cb95c28..33d3090 100644
--- a/node_modules/istanbul-lib-instrument/dist/read-coverage.js
+++ b/node_modules/istanbul-lib-instrument/dist/read-coverage.js
@@ -11,7 +11,7 @@ var _schema = require("@istanbuljs/schema");
var _constants = require("./constants");
-function getAst(code) {
+function getAst(code, filename) {
if (typeof code === 'object' && typeof code.type === 'string') {
// Assume code is already a babel ast.
return code;
@@ -21,6 +21,13 @@ function getAst(code) {
throw new Error('Code must be a string');
} // Parse as leniently as possible
+ if ( process.env.ISTANBUL_BABEL_CONFIG ) {
+ return (0, _core.parseSync)(code, {
+ babelrc: false,
+ configFile: process.env.ISTANBUL_BABEL_CONFIG,
+ filename,
+ });
+ }
return (0, _core.parseSync)(code, {
babelrc: false,
@@ -35,8 +42,8 @@ function getAst(code) {
-function readInitialCoverage(code) {
- const ast = getAst(code);
+function readInitialCoverage(code, filename) {
+ const ast = getAst(code, filename);
let covScope;
(0, _core.traverse)(ast, {
ObjectProperty(path) {
diff --git a/node_modules/nyc/lib/instrumenters/noop.js b/node_modules/nyc/lib/instrumenters/noop.js
index b0c9f70..91dbfdd 100644
--- a/node_modules/nyc/lib/instrumenters/noop.js
+++ b/node_modules/nyc/lib/instrumenters/noop.js
@@ -5,7 +5,7 @@ function NOOP () {
return {
instrumentSync (code, filename) {
- const extracted = readInitialCoverage(code)
+ const extracted = readInitialCoverage(code, filename)
if (extracted) {
this.fileCoverage = extracted.coverageData
} else {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment