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
Facebook-specific extensions for generating function maps that provide enhanced debugging support in Hermes and React Native environments.
Generate function maps from Abstract Syntax Trees (ASTs) to enable better debugging and profiling in Hermes and React Native.
/**
* Generates a function map from a Babel AST
* Function maps provide debugging information about function locations and names
* @param ast - Babel AST node (typically a Program node)
* @param context - Optional context object with filename information
* @returns Facebook-format function map with names and mappings
*/
function generateFunctionMap(ast: BabelNode, context?: Context): FBSourceFunctionMap;
/**
* Babel plugin that automatically generates function maps during transformation
* @returns Babel plugin object for integration into Babel transformation pipeline
*/
function functionMapBabelPlugin(): PluginObj;Usage Examples:
const { generateFunctionMap, functionMapBabelPlugin } = require("metro-source-map");
const parser = require("@babel/parser");
const babel = require("@babel/core");
// Generate function map from AST
const code = `
function greet(name) {
return 'Hello ' + name;
}
const calculate = (a, b) => a + b;
class Calculator {
add(x, y) {
return x + y;
}
}
`;
const ast = parser.parse(code, {
sourceType: "module",
plugins: ["jsx", "typescript"]
});
const functionMap = generateFunctionMap(ast, {});
console.log(functionMap);
// {
// names: ["greet", "calculate", "Calculator", "add"],
// mappings: "AAAA;IAII;QAII"
// }
// Use as Babel plugin
const result = babel.transformSync(code, {
plugins: [functionMapBabelPlugin()]
});
// The plugin adds function map data to the transformation result
console.log(result.metadata.functionMap);/**
* Facebook source function map format
*/
interface FBSourceFunctionMap {
/** Array of function names in order of appearance */
names: Array<string>;
/** Base64 VLQ encoded mappings for function positions */
mappings: string;
}
/**
* Facebook source metadata containing function map
*/
type FBSourceMetadata = [?FBSourceFunctionMap];
/**
* Array of source metadata for multiple sources
*/
type FBSourcesArray = Array<?FBSourceMetadata>;
/**
* Hermes function offsets for bytecode debugging
*/
interface HermesFunctionOffsets {
/** Maps function IDs to arrays of bytecode offsets */
[functionId: number]: Array<number>;
}const { generateFunctionMap, fromRawMappings } = require("metro-source-map");
const parser = require("@babel/parser");
// Generate source map with function map integration
function generateSourceMapWithFunctions(modules) {
const processedModules = modules.map(module => {
// Parse the source code to generate function map
const ast = parser.parse(module.source, {
sourceType: "module",
plugins: ["jsx", "flow"]
});
const functionMap = generateFunctionMap(ast, {});
return {
...module,
functionMap: functionMap
};
});
// Generate source map with function maps included
const generator = fromRawMappings(processedModules);
return generator.toMap();
}
// Usage
const modules = [{
map: [[1, 0, 1, 0], [2, 0, 2, 0]],
path: "src/utils.js",
source: "function helper() { return true; }",
code: "function helper() { return true; }",
isIgnored: false
}];
const sourceMapWithFunctions = generateSourceMapWithFunctions(modules);
console.log(sourceMapWithFunctions.x_facebook_sources);const { functionMapBabelPlugin } = require("metro-source-map");
const babel = require("@babel/core");
// Configure Babel with function map plugin
const babelConfig = {
plugins: [
functionMapBabelPlugin(),
// ... other plugins
],
presets: [
"@babel/preset-react",
"@babel/preset-typescript"
]
};
// Transform code with function map generation
const sourceCode = `
import React from 'react';
function MyComponent({ title }) {
const handleClick = () => {
console.log('Clicked');
};
return (
<div onClick={handleClick}>
<h1>{title}</h1>
</div>
);
}
export default MyComponent;
`;
const result = babel.transformSync(sourceCode, babelConfig);
// Access generated function map
const functionMap = result.metadata?.functionMap;
if (functionMap) {
console.log('Function names:', functionMap.names);
console.log('Function mappings:', functionMap.mappings);
}const { generateFunctionMap } = require("metro-source-map");
const parser = require("@babel/parser");
// Complex code with various function types
const complexCode = `
// Named function
function namedFunction() {}
// Arrow function
const arrowFn = () => {};
// Method in object
const obj = {
method() {},
asyncMethod: async function() {}
};
// Class with methods
class MyClass {
constructor() {}
instanceMethod() {}
static staticMethod() {}
get getter() {}
set setter(value) {}
}
// Anonymous function expression
const anonymous = function() {};
// Generator function
function* generator() {}
// Async function
async function asyncFn() {}
`;
const ast = parser.parse(complexCode, {
sourceType: "module",
plugins: ["classProperties", "asyncGenerators"]
});
const functionMap = generateFunctionMap(ast, {
// Additional options can be passed here
});
console.log('Detected functions:', functionMap.names);
// Output: All function names including constructors, methods, getters, settersconst { generateFunctionMap, fromRawMappings } = require("metro-source-map");
// Generate source maps optimized for React Native/Hermes debugging
function generateReactNativeSourceMap(modules) {
return fromRawMappings(modules.map(module => ({
...module,
// Generate function map for better Hermes debugging
functionMap: module.ast ? generateFunctionMap(module.ast, {
// Hermes-specific optimizations
includeConstructors: true,
includeGettersSetters: true
}) : null
})));
}
// Usage in Metro bundler integration
const reactNativeModules = [
{
map: rawMappings,
path: "App.js",
source: reactComponentCode,
code: transformedCode,
ast: parsedAST,
isIgnored: false
}
];
const generator = generateReactNativeSourceMap(reactNativeModules);
const sourceMap = generator.toMap("bundle.js");
// The resulting source map includes function maps for Hermes debugging
console.log(sourceMap.x_facebook_sources);
console.log(sourceMap.x_hermes_function_offsets);Function map generation may encounter errors in the following cases:
const { generateFunctionMap } = require("metro-source-map");
try {
const functionMap = generateFunctionMap(ast, options);
} catch (error) {
if (error.message.includes('Invalid AST')) {
console.error('AST is malformed:', error);
} else {
console.error('Function map generation failed:', error);
}
}
// Safe function map generation
function safeGenerateFunctionMap(ast, options = {}) {
try {
if (!ast || ast.type !== 'Program') {
return null;
}
return generateFunctionMap(ast, options);
} catch (error) {
console.warn('Function map generation failed, continuing without function map:', error);
return null;
}
}