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 building source-mapped bundles by concatenating strings and their corresponding source maps, producing indexed source maps for efficient debugging.
Main class for building bundles with source maps by concatenating code sections and composing their source maps.
/**
* Builds a source-mapped bundle by concatenating strings and their source maps
*/
class BundleBuilder {
/**
* Creates a new bundle builder
* @param file - Name of the output bundle file
*/
constructor(file: string);
/**
* Append code with optional source map to the bundle
* @param code - Code string to append
* @param map - Optional source map for the code
* @returns Self for method chaining
*/
append(code: string, map?: MixedSourceMap): this;
/**
* Get the concatenated code for the bundle
* @returns Complete bundle code
*/
getCode(): string;
/**
* Get the composed source map for the bundle
* @returns Indexed source map covering the entire bundle
*/
getMap(): MixedSourceMap;
}Usage Examples:
const { BundleBuilder } = require("metro-source-map");
// Create a bundle builder
const builder = new BundleBuilder("bundle.js");
// Append code sections with their source maps
builder
.append("// Header comment\n") // No source map
.append("console.log('module1');\n", module1SourceMap)
.append("console.log('module2');\n", module2SourceMap)
.append("// Footer\n"); // No source map
// Get the final bundle
const bundleCode = builder.getCode();
const bundleMap = builder.getMap();
console.log(bundleCode);
// Output:
// // Header comment
// console.log('module1');
// console.log('module2');
// // Footer
console.log(bundleMap.sections.length); // Number of source map sectionsUtility function for creating empty indexed source maps.
/**
* Creates an indexed source map from file and sections
* @param file - File name for the source map
* @param sections - Array of source map sections with offsets
* @returns Indexed source map structure
*/
function createIndexMap(file: string, sections: Array<IndexMapSection>): IndexMap;Usage Examples:
const { createIndexMap } = require("metro-source-map");
// Create an index map with sections
const sections = [
{
offset: { line: 0, column: 0 },
map: someBasicSourceMap
}
];
const indexMap = createIndexMap("output.js", sections);
console.log(indexMap);
// {
// version: 3,
// sections: [...],
// file: "output.js"
// }
// Use with BundleBuilder for custom initialization
const builder = new BundleBuilder("custom.js");
// Builder internally uses createIndexMapconst { BundleBuilder } = require("metro-source-map");
// Building a complex bundle with mixed content types
const builder = new BundleBuilder("app.bundle.js");
// Add a header without source map
builder.append("(function() {\n");
// Add main application modules with source maps
const modules = [
{ code: "var utils = require('./utils');\n", map: utilsSourceMap },
{ code: "var app = require('./app');\n", map: appSourceMap },
{ code: "app.start();\n", map: startSourceMap }
];
modules.forEach(({ code, map }) => {
builder.append(code, map);
});
// Add a footer without source map
builder.append("})();\n");
// Generate the final bundle
const result = {
code: builder.getCode(),
map: builder.getMap()
};
// The resulting map will be an indexed source map with sections
// corresponding to each piece of code that had an associated source map
console.log(result.map.sections.length); // Number of mapped sections/**
* Indexed source map format for bundles
*/
interface IndexMap {
/** Source map version (always 3) */
version: number;
/** Output file name */
file?: string;
/** Array of source map sections */
sections: Array<IndexMapSection>;
/** Facebook extension: byte offsets */
x_facebook_offsets?: Array<number>;
/** Metro extension: module paths */
x_metro_module_paths?: Array<string>;
/** Facebook extension: segment map */
x_facebook_segments?: FBSegmentMap;
/** Hermes extension: function offsets */
x_hermes_function_offsets?: HermesFunctionOffsets;
/** These fields are void in IndexMap to maintain type safety */
mappings?: void;
sourcesContent?: void;
x_facebook_sources?: void;
x_google_ignoreList?: void;
}
/**
* Individual section within an indexed source map
*/
interface IndexMapSection {
/** Source map for this section (can be basic or indexed) */
map: IndexMap | BasicSourceMap;
/** Offset where this section starts in the bundle */
offset: {
/** Line offset (0-based) */
line: number;
/** Column offset (0-based) */
column: number;
};
}const { BundleBuilder, Generator, fromRawMappings } = require("metro-source-map");
// Building a bundle using generated source maps
const builder = new BundleBuilder("output.js");
// Generate source maps for individual modules
const module1Map = fromRawMappings([{
map: [[1, 0, 1, 0], [1, 8, 1, 8]],
path: "src/module1.js",
source: "console.log('one');",
code: "console.log('one');",
isIgnored: false
}]).toMap();
const module2Map = fromRawMappings([{
map: [[1, 0, 1, 0], [1, 8, 1, 8]],
path: "src/module2.js",
source: "console.log('two');",
code: "console.log('two');",
isIgnored: false
}]).toMap();
// Build the bundle
builder
.append("console.log('one');\n", module1Map)
.append("console.log('two');\n", module2Map);
const finalMap = builder.getMap();
// finalMap will be an IndexMap with 2 sectionsBundleBuilder operations may encounter errors in the following cases:
getMap() or getCode() is called before any content is appendedconst { BundleBuilder } = require("metro-source-map");
try {
const builder = new BundleBuilder("test.js");
builder.append("console.log('test');", invalidSourceMap);
const map = builder.getMap();
} catch (error) {
console.error('Bundle building failed:', error);
}
// Safe usage with validation
const builder = new BundleBuilder("safe.js");
if (someCode && someCode.length > 0) {
builder.append(someCode, optionalSourceMap);
}