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
Functionality for reading and querying source maps with support for both basic and indexed source map formats, including Facebook and Hermes extensions.
Main class for consuming and querying source maps. Automatically handles both basic and indexed source map formats.
/**
* Source map consumer supporting both basic and indexed formats
*/
class Consumer {
/** Iteration order constant for generated positions */
static GENERATED_ORDER: IterationOrder;
/** Iteration order constant for original positions */
static ORIGINAL_ORDER: IterationOrder;
/** Lookup bias for greatest lower bound searches */
static GREATEST_LOWER_BOUND: LookupBias;
/** Lookup bias for least upper bound searches */
static LEAST_UPPER_BOUND: LookupBias;
/**
* Creates a consumer for the given source map
* @param sourceMap - Source map object (basic or indexed format)
*/
constructor(sourceMap: MixedSourceMap);
/**
* Find the original position for a generated position
* @param generatedPosition - Generated line/column with optional bias
* @returns Original source position or null if not found
*/
originalPositionFor(generatedPosition: GeneratedPositionLookup): SourcePosition;
/**
* Get an iterable of all mappings in generated order
* @returns Iterable of all mappings in the source map
*/
generatedMappings(): Iterable<Mapping>;
/**
* Iterate over all mappings in the source map
* @param callback - Function called for each mapping
* @param context - Optional context object for callback
* @param order - Optional iteration order (GENERATED_ORDER or ORIGINAL_ORDER)
*/
eachMapping(
callback: (mapping: Mapping) => mixed,
context?: mixed,
order?: IterationOrder
): void;
/**
* Get the file name associated with this source map
* @returns Source map file name or null
*/
get file(): ?string;
/**
* Get the source content for a given source file
* @param source - Source file path
* @param nullOnMissing - Must be true, returns null if source not found
* @returns Source file content or null
*/
sourceContentFor(source: string, nullOnMissing: true): ?string;
}Usage Examples:
const { Consumer } = require("metro-source-map");
// Create consumer from a source map
const sourceMap = {
version: 3,
sources: ["src/app.js"],
names: ["console", "log"],
mappings: "AAAA,QAAQ,CAAC,GAAG",
sourcesContent: ["console.log('hello');"]
};
const consumer = new Consumer(sourceMap);
// Find original position for generated position
const originalPos = consumer.originalPositionFor({
line: 1,
column: 8,
bias: Consumer.GREATEST_LOWER_BOUND
});
console.log(originalPos);
// { source: "src/app.js", line: 1, column: 8, name: null }
// Get source content
const sourceContent = consumer.sourceContentFor("src/app.js", true);
console.log(sourceContent);
// "console.log('hello');"
// Get all mappings as an iterable
const mappings = consumer.generatedMappings();
for (const mapping of mappings) {
console.log(`Generated: ${mapping.generatedLine}:${mapping.generatedColumn}`);
console.log(`Original: ${mapping.originalLine}:${mapping.originalColumn}`);
}
// Or iterate over all mappings with callback
consumer.eachMapping((mapping) => {
console.log(`Generated: ${mapping.generatedLine}:${mapping.generatedColumn}`);
console.log(`Original: ${mapping.originalLine}:${mapping.originalColumn}`);
console.log(`Source: ${mapping.source}`);
console.log(`Name: ${mapping.name}`);
});Types representing positions in generated and original source code.
/**
* Position in original source code
*/
interface SourcePosition {
/** Source file path */
source: ?string;
/** Line number (1-based) */
line: ?number;
/** Column number (0-based) */
column: ?number;
/** Symbol name at this position */
name: ?string;
}
/**
* Generated position lookup with optional bias
*/
interface GeneratedPositionLookup {
/** Line number (1-based), null to match any line */
line: ?number;
/** Column number (0-based), null to match any column */
column: ?number;
/** Search bias for inexact matches */
bias?: LookupBias;
}
/**
* Complete mapping information
*/
interface Mapping {
/** Source file path */
source: ?string;
/** Generated line number (1-based) */
generatedLine: number;
/** Generated column number (0-based) */
generatedColumn: number;
/** Original line number (1-based) */
originalLine: ?number;
/** Original column number (0-based) */
originalColumn: ?number;
/** Symbol name */
name: ?string;
}/**
* Iteration order for eachMapping
*/
type IterationOrder = "GENERATED_ORDER" | "ORIGINAL_ORDER";
/**
* Lookup bias for position searches
*/
type LookupBias = "GREATEST_LOWER_BOUND" | "LEAST_UPPER_BOUND";
/**
* ob1 number types (1-based and 0-based)
*/
// Note: All numeric positions use regular number type
// Line numbers are typically 1-based, column numbers are 0-basedconst { Consumer } = require("metro-source-map");
// Working with indexed source maps
const indexedMap = {
version: 3,
sections: [
{
offset: { line: 0, column: 0 },
map: {
version: 3,
sources: ["module1.js"],
names: ["fn1"],
mappings: "AAAA"
}
},
{
offset: { line: 10, column: 0 },
map: {
version: 3,
sources: ["module2.js"],
names: ["fn2"],
mappings: "AAAA"
}
}
]
};
const consumer = new Consumer(indexedMap);
// Search with bias for inexact matches
const result = consumer.originalPositionFor({
line: 5,
column: 10,
bias: Consumer.GREATEST_LOWER_BOUND
});
// Iterate in original source order
consumer.eachMapping((mapping) => {
console.log(`${mapping.source}:${mapping.originalLine}:${mapping.originalColumn}`);
}, null, Consumer.ORIGINAL_ORDER);
// Handle missing source content gracefully
const content = consumer.sourceContentFor("missing.js", true);
if (content === null) {
console.log("Source content not available");
}Consumer methods may encounter the following error conditions:
sourceContentFor is called without nullOnMissing=truetry {
const consumer = new Consumer(sourceMap);
const position = consumer.originalPositionFor({ line: 1, column: 0 });
} catch (error) {
console.error('Source map consumption failed:', error);
}
// Safe source content access
const content = consumer.sourceContentFor("app.js", true);
if (content === null) {
console.warn("Source content not available for app.js");
}