or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

index.mddocs/

babel-plugin-istanbul

babel-plugin-istanbul is a Babel plugin that automatically instruments JavaScript code with Istanbul coverage tracking during compilation. It enables code coverage analysis for ES6+ code by transforming the source code to include coverage counters, making it compatible with testing frameworks like Mocha and Karma.

Package Information

  • Package Name: babel-plugin-istanbul
  • Package Type: npm
  • Language: JavaScript/TypeScript
  • Installation: npm install --save-dev babel-plugin-istanbul

Core Imports

// ESM import (for programmatic usage)
import babelPluginIstanbul from "babel-plugin-istanbul";

// CommonJS (for programmatic usage)
const babelPluginIstanbul = require("babel-plugin-istanbul");

Basic Usage

Babel Configuration

Add the plugin to your .babelrc or babel.config.js in test mode:

{
  "env": {
    "test": {
      "plugins": ["istanbul"]
    }
  }
}

With options:

{
  "env": {
    "test": {
      "plugins": [
        ["istanbul", {
          "exclude": ["**/*.spec.js", "test/**"],
          "useInlineSourceMaps": false
        }]
      ]
    }
  }
}

Programmatic Usage

import babel from "@babel/core";
import babelPluginIstanbul from "babel-plugin-istanbul";

const result = babel.transform(sourceCode, {
  filename: "example.js",
  plugins: [
    [babelPluginIstanbul, {
      include: ["src/**/*.js"],
      exclude: ["src/**/*.test.js"],
      onCover: (filePath, fileCoverage) => {
        console.log(`Instrumented: ${filePath}`);
      }
    }]
  ]
});

Architecture

The plugin operates as a Babel AST visitor that:

  • Configuration Resolution: Loads configuration from plugin options, nyc config, or environment variables
  • File Filtering: Uses test-exclude patterns to determine which files to instrument
  • AST Instrumentation: Wraps the istanbul-lib-instrument programVisitor to inject coverage tracking code
  • Source Map Handling: Preserves and processes source maps for accurate coverage reporting
  • Integration Points: Provides callbacks and works with karma-coverage and nyc

Capabilities

Babel Plugin Export

The main export that creates the Babel plugin for code instrumentation.

/**
 * Creates a Babel plugin that instruments code with Istanbul coverage
 * @param {Object} api - Babel API object
 * @returns {Object} Babel plugin object with visitor pattern
 */
function babelPluginIstanbul(api: BabelAPI): BabelPlugin;

interface BabelPlugin {
  visitor: {
    Program: {
      enter(path: NodePath): void;
      exit(path: NodePath): void;
    };
  };
}

interface BabelAPI {
  types: Object;
  assertVersion(version: number): void;
}

Plugin Configuration Options

Configuration object passed as the second parameter to the plugin:

interface PluginOptions {
  /** Array of glob patterns for files to include */
  include?: string[];
  /** Array of glob patterns for files to exclude */
  exclude?: string[];
  /** Whether to exclude node_modules (default: true) */
  excludeNodeModules?: boolean;
  /** File extensions to consider for instrumentation */
  extension?: string[];
  /** Global variable name for coverage data (default: '__coverage__') */
  coverageVariable?: string;
  /** Scope for coverage variable ('window', 'global', etc.) */
  coverageGlobalScope?: string;
  /** Whether to use function to determine global scope (default: true) */
  coverageGlobalScopeFunc?: boolean;
  /** Whether to use inline source maps (default: true) */
  useInlineSourceMaps?: boolean;
  /** Explicitly provided source map object */
  inputSourceMap?: Object;
  /** Array of class method names to ignore in instrumentation */
  ignoreClassMethods?: string[];
  /** Current working directory for config resolution */
  cwd?: string;
  /** Path to .nycrc configuration file */
  nycrcPath?: string;
  /** Callback executed when a file is instrumented */
  onCover?: (filePath: string, fileCoverage: Object) => void;
}

File Coverage Callback

The onCover callback provides access to coverage data for each instrumented file:

/**
 * Callback executed when a file is instrumented
 * @param {string} filePath - Absolute path to the instrumented file
 * @param {Object} fileCoverage - Istanbul file coverage object
 */
function onCover(filePath: string, fileCoverage: FileCoverage): void;

interface FileCoverage {
  /** Mapping of statement locations */
  statementMap: { [key: string]: Location };
  /** Mapping of function locations */
  fnMap: { [key: string]: FunctionLocation };
  /** Mapping of branch locations */
  branchMap: { [key: string]: BranchLocation };
  /** Statement execution counts */
  s: { [key: string]: number };
  /** Function execution counts */
  f: { [key: string]: number };
  /** Branch execution counts */
  b: { [key: string]: number[] };
}

interface Location {
  start: { line: number; column: number };
  end: { line: number; column: number };
}

interface FunctionLocation extends Location {
  name: string;
  decl: Location;
  loc: Location;
}

interface BranchLocation {
  loc: Location;
  type: string;
  locations: Location[];
}

Integration with Testing Frameworks

Karma Integration

Works automatically with karma-coverage when Babel transpilation is already configured:

// karma.conf.js
module.exports = function(config) {
  config.set({
    preprocessors: {
      'src/**/*.js': ['babel'] // Don't add 'coverage' preprocessor
    },
    coverageReporter: {
      type: 'html',
      dir: 'coverage/'
    }
  });
};

NYC Integration

Configure NYC to not instrument code (plugin handles instrumentation):

{
  "nyc": {
    "sourceMap": false,
    "instrument": false,
    "include": ["src/**/*.js"],
    "exclude": ["src/**/*.test.js"]
  }
}

Configuration Resolution

The plugin resolves configuration from multiple sources in order of precedence:

  1. Plugin Options: Explicit options passed to the plugin
  2. Environment Variables: NYC_CONFIG environment variable
  3. NYC Configuration: .nycrc, .nycrc.json, or package.json nyc section
  4. Default Values: Built-in defaults from @istanbuljs/schema
/**
 * Resolves final configuration from multiple sources
 * @param {Object} opts - Plugin options
 * @returns {Object} Resolved configuration object
 */
function findConfig(opts: PluginOptions): ResolvedConfig;

interface ResolvedConfig extends PluginOptions {
  cwd: string;
  include: string[];
  exclude: string[];
  excludeNodeModules: boolean;
  extension: string[];
  coverageVariable: string;
  useInlineSourceMaps: boolean;
}

Source Map Integration

The plugin handles source maps to maintain coverage accuracy across build steps:

/**
 * Source map options for coverage instrumentation
 */
interface SourceMapOptions {
  /** Whether to use inline source maps from the source code */
  useInlineSourceMaps?: boolean;
  /** Explicitly provided source map object */
  inputSourceMap?: {
    version: number;
    sources: string[];
    names: string[];
    mappings: string;
    sourcesContent?: string[];
  };
}

Usage Examples

Custom Coverage Variable

// babel.config.js
module.exports = {
  env: {
    test: {
      plugins: [
        ["istanbul", {
          coverageVariable: "__MY_COVERAGE__"
        }]
      ]
    }
  }
};

File Filtering

// .babelrc
{
  "env": {
    "test": {
      "plugins": [
        ["istanbul", {
          "include": ["src/**/*.js"],
          "exclude": [
            "src/**/*.test.js",
            "src/**/*.spec.js",
            "src/test-utils/**"
          ]
        }]
      ]
    }
  }
}

Coverage Callback Usage

import babel from "@babel/core";
import babelPluginIstanbul from "babel-plugin-istanbul";

const coverageData = new Map();

babel.transform(code, {
  plugins: [
    [babelPluginIstanbul, {
      onCover: (filePath, fileCoverage) => {
        coverageData.set(filePath, fileCoverage);
        console.log(`Instrumented ${filePath} with ${Object.keys(fileCoverage.statementMap).length} statements`);
      }
    }]
  ]
});

Ignoring Class Methods

// babel.config.js
module.exports = {
  env: {
    test: {
      plugins: [
        ["istanbul", {
          ignoreClassMethods: ["render", "componentDidMount"]
        }]
      ]
    }
  }
};

Browser vs Node.js Configuration

// For browser testing (with window global)
{
  "plugins": [
    ["istanbul", {
      "coverageGlobalScope": "window"
    }]
  ]
}

// For Node.js testing (with global object)
{
  "plugins": [
    ["istanbul", {
      "coverageGlobalScope": "global"
    }]
  ]
}

Error Handling

The plugin handles several error scenarios gracefully:

  • File Resolution Errors: Falls back to original path if realpath resolution fails
  • Configuration Errors: Throws descriptive errors for invalid nyc configuration
  • Instrumentation Skipping: Silently skips files that match exclude patterns
  • Source Map Errors: Continues instrumentation without source maps if parsing fails

Common error patterns:

// Configuration loading error
throw new Error("Failed to load nyc configuration: Invalid JSON in .nycrc");

// File filtering (no error, just skipped)
if (shouldSkip(filePath, nycConfig)) {
  return; // File not instrumented
}