CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-symbolicate

A tool to find the source location from JS bundles and stack traces.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

source-metadata.mddocs/

Source Metadata Processing

Enhanced source map processing with support for function names and Facebook-specific metadata extensions.

Capabilities

SourceMetadataMapConsumer Class

Processes x_facebook_sources metadata from source maps to provide function name resolution and enhanced debugging information.

/**
 * Consumes Facebook-specific source map metadata for function name resolution
 * @param map - Source map object (BasicSourceMap or IndexMap)
 * @param normalizeSourceFn - Optional function to normalize source names
 */
class SourceMetadataMapConsumer {
  constructor(map: MixedSourceMap, normalizeSourceFn?: SourceNameNormalizer);
  
  /**
   * Gets function name for a specific source location
   * @param {line, column, source} - Object containing location details
   * @returns Function name at the location, or null if not found
   */
   functionNameFor({line, column, source}: {line: number, column: number, source: ?string}): ?string;
  
  /**
   * Returns this map's source metadata as a new array with the same order as sources
   * @param sources - Array of source names
   * @returns Array of metadata objects for each source
   */
  toArray(sources: Array<string>): Array<?{[number]: any}>;
}

Usage Examples:

const SourceMetadataMapConsumer = require('metro-symbolicate/private/SourceMetadataMapConsumer');
const fs = require('fs');

// Load source map with metadata
const sourceMap = JSON.parse(fs.readFileSync('bundle.js.map', 'utf8'));
const metadataConsumer = new SourceMetadataMapConsumer(sourceMap);

// Get function name for a location
const functionName = metadataConsumer.functionNameFor({
  source: 'src/utils.js', 
  line: 15, 
  column: 8
});
if (functionName) {
  console.log(`Function at src/utils.js:15:8 is: ${functionName}`);
}

// Convert metadata to array format
const sources = ['src/app.js', 'src/utils.js'];
const metadataArray = metadataConsumer.toArray(sources);
console.log('Metadata for sources:', metadataArray);

Function Name Resolution

Provides enhanced function name resolution beyond standard source map capabilities, particularly useful for React Native and Metro bundles.

Function Name vs Identifier Names:

Metro source maps can contain two types of name information:

  • Function names: Actual function declarations and expressions (function myFunction(), const myFunc = () => {})
  • Identifier names: Variable and property names at specific locations
// Example source code:
const utils = {
  processData: function validateAndProcess(input) {
    return input.trim();
  }
};

// Function name: "validateAndProcess" 
// Identifier name: "processData" (property name), "input" (parameter), "trim" (method call)

Usage Examples:

const SourceMetadataMapConsumer = require('metro-symbolicate/private/SourceMetadataMapConsumer');

// Create consumer with default normalization
const consumer = new SourceMetadataMapConsumer(sourceMap);

// Create consumer with custom source name normalization
const customConsumer = new SourceMetadataMapConsumer(sourceMap, (source, options) => {
  // Custom normalization logic
  return source.replace(/^webpack:\/\/\//, '');
});

// Function name resolution examples
const functionName = consumer.functionNameFor({source: 'src/api.js', line: 42, column: 10});
switch (functionName) {
  case null:
    console.log('No function name available');
    break;
  default:
    console.log(`Function: ${functionName}`);
}

Source Map Metadata Integration

Seamlessly integrates with standard source map processing while providing enhanced metadata capabilities.

Source Map Compatibility:

type MixedSourceMap = BasicSourceMap | IndexMap;

type BasicSourceMap = {
  version: number;
  sources: Array<string>;
  names: Array<string>;
  mappings: string;
  file?: string;
  sourceRoot?: string;
  sourcesContent?: Array<?string>;
  x_facebook_sources?: FBSourcesArray;
};

type IndexMap = {
  version: number;
  file?: string;
  sections: Array<IndexMapSection>;
  x_facebook_sources?: FBSourcesArray;
};

type SourceNameNormalizer = (
  source: string,
  options: { sourceRoot?: ?string }
) => string;

Usage Examples:

// Working with different source map types
const processSourceMap = (sourceMapData) => {
  const consumer = new SourceMetadataMapConsumer(sourceMapData);
  
  // Handle both basic and indexed source maps
  if (sourceMapData.sections) {
    console.log('Processing indexed source map');
  } else {
    console.log('Processing basic source map');
  }
  
  // Function name resolution works for both types
  return consumer.functionNameFor({source: 'src/main.js', line: 1, column: 0});
};

VLQ Decoding Support

Handles Variable Length Quantity (VLQ) encoding used in Facebook source map extensions for compact metadata storage.

Internal VLQ Processing:

The SourceMetadataMapConsumer automatically handles VLQ-encoded function map data:

// VLQ-encoded function mappings are automatically decoded
// No direct VLQ manipulation needed by consumers

// Example: checking for function name availability
const fname = consumer.functionNameFor({source: 'src/complex-component.js', line: 100, column: 25});
if (fname) {
  // Function map data has been successfully decoded from VLQ format
  console.log(`Decoded function name: ${fname}`);
}

Error Handling

Graceful handling of missing or invalid metadata without breaking standard source map functionality.

Error Scenarios:

const consumer = new SourceMetadataMapConsumer(sourceMap);

// Missing function map - returns null, doesn't throw
const missingFunction = consumer.functionNameFor({source: 'nonexistent.js', line: 1, column: 1});
console.log(missingFunction); // null

// Invalid coordinates - returns null gracefully  
const invalidCoords = consumer.functionNameFor({source: 'src/app.js', line: -1, column: -1});
console.log(invalidCoords); // null

// Check availability before querying
const source = 'src/utils.js';
const functionName = consumer.functionNameFor({source, line: 50, column: 10});
if (functionName) {
  // Safe to use functionName, function map exists
} else {
  console.log(`No function map available for ${source}`);
}

Types

type FBSourcesArray = Array<?FBSourceMetadata>;

type FBSourceMetadata = Array<FBSourceMetadataField>;

type FBSourceMetadataField = FBSourceFunctionMap;

type FBSourceFunctionMap = {
  names: Array<string>;
  mappings: string; // VLQ-encoded function mappings
};

type Position = {
  line: number;
  column: number;
};

type FunctionMapping = {
  line: number;
  column: number;
  name: string;
};

type MetadataMap = { [source: string]: ?FBSourceMetadata };

docs

chrome-devtools.md

cli-interface.md

core-symbolication.md

ignore-list.md

index.md

source-metadata.md

tile.json