Source map generator for Metro bundler with advanced mapping capabilities and Facebook/Hermes extensions.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core functionality for creating source maps from raw mappings with support for Metro's specific requirements, Facebook extensions, and Hermes integration.
Create source maps from raw mappings data, which are arrays of tuples representing the relationship between generated and original code positions.
/**
* Creates a source map from modules with raw mappings (synchronous)
* @param modules - Array of module objects with mappings and metadata
* @param offsetLines - Number of lines to offset in the resulting bundle
* @returns Generator instance for creating the final source map
*/
function fromRawMappings(
modules: Array<{
map: ?Array<MetroSourceMapSegmentTuple>,
functionMap: ?FBSourceFunctionMap,
path: string,
source: string,
code: string,
isIgnored: boolean,
lineCount?: number
}>,
offsetLines?: number = 0
): Generator;
/**
* Creates a source map from modules with raw mappings (asynchronous, non-blocking)
* @param modules - Array of module objects with mappings and metadata
* @param offsetLines - Number of lines to offset in the resulting bundle
* @returns Promise resolving to Generator instance
*/
function fromRawMappingsNonBlocking(
modules: Array<{
map: ?Array<MetroSourceMapSegmentTuple>,
functionMap: ?FBSourceFunctionMap,
path: string,
source: string,
code: string,
isIgnored: boolean,
lineCount?: number
}>,
offsetLines?: number = 0
): Promise<Generator>;Usage Examples:
const { fromRawMappings, fromRawMappingsNonBlocking } = require("metro-source-map");
// Synchronous generation
const modules = [
{
map: [
[1, 0, 1, 0], // Line 1, Col 0 -> Line 1, Col 0
[1, 12, 1, 12, "log"], // Line 1, Col 12 -> Line 1, Col 12, name "log"
[2, 0, 2, 0] // Line 2, Col 0 -> Line 2, Col 0
],
functionMap: null,
path: "src/utils.js",
source: "console.log('hello');\nmodule.exports = {};",
code: "console.log('hello');\nmodule.exports = {};",
isIgnored: false,
lineCount: 2
}
];
const generator = fromRawMappings(modules, 0);
const sourceMap = generator.toMap("bundle.js");
// Asynchronous generation (non-blocking)
const generatorAsync = await fromRawMappingsNonBlocking(modules, 0);
const sourceMapAsync = generatorAsync.toMap("bundle.js");The Generator class is used internally by fromRawMappings functions. It is not directly exported but is returned by those functions for building source maps incrementally.
/**
* Generator class for creating source maps from raw mappings
* (Returned by fromRawMappings functions, not directly constructible)
*/
class Generator {
/**
* Start processing a new source file
* @param file - Path to the source file
* @param code - Source code content for the file
* @param functionMap - Optional Facebook function map for debugging
* @param options - Optional file processing flags
*/
startFile(
file: string,
code: string,
functionMap?: FBSourceFunctionMap,
options?: FileFlags
): void;
/**
* End processing of the current source file
*/
endFile(): void;
/**
* Add a simple mapping (generated position only)
* @param line - Generated line number (1-based)
* @param column - Generated column number (0-based)
*/
addSimpleMapping(line: number, column: number): void;
/**
* Add a source mapping (generated to original position)
* @param line - Generated line number (1-based)
* @param column - Generated column number (0-based)
* @param originalLine - Original line number (1-based)
* @param originalColumn - Original column number (0-based)
*/
addSourceMapping(
line: number,
column: number,
originalLine: number,
originalColumn: number
): void;
/**
* Add a named source mapping (includes symbol name)
* @param line - Generated line number (1-based)
* @param column - Generated column number (0-based)
* @param originalLine - Original line number (1-based)
* @param originalColumn - Original column number (0-based)
* @param name - Symbol name in original source
*/
addNamedSourceMapping(
line: number,
column: number,
originalLine: number,
originalColumn: number,
name: string
): void;
/**
* Generate the final source map object
* @param file - Optional file name for the generated source map
* @param options - Optional generation options
* @returns Complete source map object
*/
toMap(file?: string, options?: {excludeSource?: boolean}): BasicSourceMap;
/**
* Serialize the source map to a JSON string
* @param file - Optional file name for the generated source map
* @param options - Optional generation options
* @returns JSON string representation of the source map
*/
toString(file?: string, options?: {excludeSource?: boolean}): string;
}Usage Examples:
const { fromRawMappings } = require("metro-source-map");
// Get Generator instance through fromRawMappings
const modules = [/* ... */];
const generator = fromRawMappings(modules);
// Start a file
generator.startFile("src/app.js", "console.log('hello');", null, { addToIgnoreList: false });
// Add mappings
generator.addSimpleMapping(1, 0); // Generated only
generator.addSourceMapping(1, 8, 1, 8); // Generated -> Original
generator.addNamedSourceMapping(1, 12, 1, 12, "console"); // With name
// End the file
generator.endFile();
// Generate the source map
const sourceMap = generator.toMap("dist/bundle.js");
console.log(sourceMap.mappings); // Base64 VLQ encoded mappingsRaw mapping segments can have 2, 4, or 5 elements representing different levels of mapping detail.
/**
* Metro source map segment tuple formats:
* - GeneratedCodeMapping: [generatedLine, generatedColumn]
* - SourceMapping: [generatedLine, generatedColumn, originalLine, originalColumn]
* - SourceMappingWithName: [generatedLine, generatedColumn, originalLine, originalColumn, symbolName]
*/
type MetroSourceMapSegmentTuple =
| [number, number] // Generated position only
| [number, number, number, number] // Generated -> Original position
| [number, number, number, number, string]; // Generated -> Original position + name
/**
* File processing options
*/
interface FileFlags {
/** Whether to add this file to the ignore list for debugging */
addToIgnoreList?: boolean;
}The generation functions and Generator class methods may throw errors in the following cases:
try {
const generator = fromRawMappings(modules);
const sourceMap = generator.toMap();
} catch (error) {
if (error.message.includes('Invalid mapping')) {
console.error('Mapping data is malformed:', error);
}
}