Source maps support for Istanbul code coverage toolkit, enabling accurate coverage reporting for transpiled JavaScript code
npx @tessl/cli install tessl/npm-istanbul-lib-source-maps@5.0.0Istanbul Lib Source Maps provides source map support for the Istanbul code coverage toolkit, enabling accurate coverage reporting for transpiled JavaScript code. It manages source map resolution and transformation to map coverage data from generated code back to original source files, supporting various source map formats and providing utilities for storing, retrieving, and processing source map information.
npm install istanbul-lib-source-mapsconst { createSourceMapStore } = require("istanbul-lib-source-maps");For internal classes (not typically needed by end users):
const { MapStore } = require("istanbul-lib-source-maps/lib/map-store");
const { SourceMapTransformer } = require("istanbul-lib-source-maps/lib/transformer");
const { MappedCoverage } = require("istanbul-lib-source-maps/lib/mapped");const { createSourceMapStore } = require("istanbul-lib-source-maps");
// Create a source map store
const store = createSourceMapStore({
verbose: false,
baseDir: process.cwd()
});
// Register source maps
store.registerURL('/path/to/built/file.js', './file.js.map');
store.registerMap('/path/to/built/file.js', sourceMapObject);
// Transform coverage to original sources
const transformedCoverage = await store.transformCoverage(coverageMap);
// Clean up resources
store.dispose();Istanbul Lib Source Maps is built around several key components:
Creates and configures source map stores for tracking and transforming coverage data.
/**
* Creates a new MapStore instance for tracking source maps
* @param {Object} opts - Configuration options for the MapStore
* @returns {MapStore} MapStore instance
*/
function createSourceMapStore(opts);Central class for managing source maps and transforming coverage data to original sources.
class MapStore {
/**
* @param {Object} opts - Configuration options
* @param {Boolean} opts.verbose - Enable verbose logging (default: false)
* @param {String} opts.baseDir - Alternate base directory for sourcemap resolution (default: null)
* @param {Class} opts.SourceStore - Class for source storage (default: Map)
* @param {Array} opts.sourceStoreOpts - Arguments for SourceStore constructor (default: [])
*/
constructor(opts);
/**
* Registers a source map URL with this store
* @param {String} transformedFilePath - File path for which the source map is valid
* @param {String} sourceMapUrl - Source map URL (not a comment)
*/
registerURL(transformedFilePath, sourceMapUrl);
/**
* Registers a source map object with this store
* @param {String} transformedFilePath - File path for which the source map is valid
* @param {Object} sourceMap - Source map object with version property
*/
registerMap(transformedFilePath, sourceMap);
/**
* Retrieve a source map object from this store synchronously
* @param {String} filePath - File path to get source map for
* @returns {Object|undefined} Parsed source map object or undefined if not found
*/
getSourceMapSync(filePath);
/**
* Add inputSourceMap property to coverage data entries
* @param {Object} coverageData - The __coverage__ object
*/
addInputSourceMapsSync(coverageData);
/**
* Transforms coverage map to refer to original sources using registered mappings
* @param {CoverageMap} coverageMap - Coverage map to transform
* @returns {Promise<CoverageMap>} Transformed coverage map
*/
async transformCoverage(coverageMap);
/**
* Disposes temporary resources allocated by this map store
*/
dispose();
/**
* Internal method to find source content for a file path
* @param {String} filePath - Path to source file
* @returns {String} Source file content
*/
sourceFinder(filePath);
}Core transformation engine that processes coverage data through source maps.
class SourceMapTransformer {
/**
* @param {Function} finder - Async function to find source maps for files
* @param {Object} opts - Options including baseDir and custom getMapping function
* @param {String} opts.baseDir - Base directory for path resolution (default: process.cwd())
* @param {Function} opts.getMapping - Custom mapping function (default: built-in getMapping)
*/
constructor(finder, opts);
/**
* Transform a coverage map using source maps
* @param {CoverageMap} coverageMap - Coverage map to transform
* @returns {Promise<CoverageMap>} Transformed coverage map
*/
async transform(coverageMap);
/**
* Process a single file's coverage data with its source map
* @param {FileCoverage} fc - File coverage object
* @param {SourceMap} sourceMap - Source map for the file
* @param {Function} coverageMapper - Function to get mapped coverage for a source file
* @returns {Boolean} Whether any changes were made
*/
processFile(fc, sourceMap, coverageMapper);
}Specialized coverage object that accumulates mapped statements, functions, and branches from source-mapped files.
class MappedCoverage extends FileCoverage {
/**
* @param {String|Object} pathOrObj - File path or existing coverage object
*/
constructor(pathOrObj);
/**
* Add a statement mapping with hit count
* @param {Object} loc - Location object with start/end positions
* @param {Number} hits - Number of times statement was hit
* @returns {Number} Statement index
*/
addStatement(loc, hits);
/**
* Add a function mapping with hit count
* @param {String} name - Function name (auto-generated if not provided)
* @param {Object} decl - Declaration location object
* @param {Object} loc - Function body location object
* @param {Number} hits - Number of times function was called
* @returns {Number} Function index
*/
addFunction(name, decl, loc, hits);
/**
* Add a branch mapping with hit counts
* @param {String} type - Branch type (e.g., 'if', 'switch')
* @param {Object} loc - Branch location object
* @param {Array<Object>} branchLocations - Array of branch location objects
* @param {Array<Number>} hits - Array of hit counts for each branch
* @returns {Number} Branch index
*/
addBranch(type, loc, branchLocations, hits);
/**
* Clone a location object with only essential attributes
* @param {Object} loc - Location object to clone
* @returns {Object} Cloned location object with start/end properties
*/
cloneLocation(loc);
}Helper functions for source mapping, path resolution, and data transformation.
/**
* Determines original position for a generated location using source map
* @param {SourceMap} sourceMap - Source map object
* @param {Object} generatedLocation - Generated location with start/end positions
* @param {String} origFile - Original file path
* @returns {Object|null} Mapping object with source and loc properties, or null
*/
function getMapping(sourceMap, generatedLocation, origFile);
/**
* Generate unique key from pathname by replacing slashes
* @param {String} pathname - File pathname
* @returns {String} Unique key with slashes replaced by underscores
*/
function getUniqueKey(pathname);
/**
* Convert cache object to output format for coverage data
* @param {Object} cache - Cache with file/mappedCoverage entries
* @returns {Object} Coverage output object
*/
function getOutput(cache);
/**
* Check if path is absolute
* @param {String} file - File path
* @returns {Boolean} True if path is absolute
*/
function isAbsolute(file);
/**
* Convert relative path to absolute using baseDir
* @param {String} file - File path
* @param {String} baseDir - Base directory (defaults to process.cwd())
* @returns {String} Absolute file path
*/
function asAbsolute(file, baseDir);
/**
* Resolve file path relative to origFile directory
* @param {String} file - File path to resolve
* @param {String} origFile - Original file to resolve relative to
* @returns {String} Resolved file path
*/
function relativeTo(file, origFile);/**
* Configuration options for MapStore
*/
interface MapStoreOptions {
verbose?: boolean; // Enable verbose logging (default: false)
baseDir?: string; // Alternate base directory (default: null)
SourceStore?: Class; // Storage class (default: Map)
sourceStoreOpts?: Array; // Storage constructor arguments (default: [])
}
/**
* Location object representing code positions
*/
interface Location {
start: {
line: number;
column: number;
};
end: {
line: number;
column: number;
};
}
/**
* Source map mapping result
*/
interface MappingResult {
source: string; // Original source file path
loc: Location; // Location in original source
}
/**
* Coverage map interface (from istanbul-lib-coverage)
*/
interface CoverageMap {
files(): Array<string>;
fileCoverageFor(file: string): FileCoverage;
}
/**
* File coverage interface (from istanbul-lib-coverage)
*/
interface FileCoverage {
path: string;
statementMap: Object;
fnMap: Object;
branchMap: Object;
s: Object; // Statement hit counts
f: Object; // Function hit counts
b: Object; // Branch hit counts
data: Object; // Raw coverage data
}The library handles various error conditions gracefully:
Enable debug logging with DEBUG=istanbuljs environment variable to see detailed error information.
const libCoverage = require('istanbul-lib-coverage');
const { createSourceMapStore } = require('istanbul-lib-source-maps');
async function processCoverage(coverageData) {
// Create coverage map from raw coverage data
const coverageMap = libCoverage.createCoverageMap(coverageData);
// Create source map store
const store = createSourceMapStore({
verbose: true,
baseDir: '/project/root'
});
// Register source maps for transformed files
store.registerURL('/build/app.js', '/build/app.js.map');
store.registerURL('/build/utils.js', '/build/utils.js.map');
// Transform coverage to original sources
const transformedCoverage = await store.transformCoverage(coverageMap);
// Clean up
store.dispose();
return transformedCoverage;
}const fs = require('fs');
const { createSourceMapStore } = require('istanbul-lib-source-maps');
const store = createSourceMapStore();
// Register from file
const sourceMapContent = fs.readFileSync('./dist/bundle.js.map', 'utf8');
const sourceMapObject = JSON.parse(sourceMapContent);
store.registerMap('./dist/bundle.js', sourceMapObject);
// Register inline source map
store.registerURL('./dist/inline.js',
'data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjo...');
// Register external source map
store.registerURL('./dist/external.js', './external.js.map');