CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-source-map

Source map generator for Metro bundler with advanced mapping capabilities and Facebook/Hermes extensions.

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

consumption.mddocs/

Source Map Consumption

Functionality for reading and querying source maps with support for both basic and indexed source map formats, including Facebook and Hermes extensions.

Capabilities

Consumer Class

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}`);
});

Position Types

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;
}

Constants and Types

/**
 * 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-based

Advanced Usage

const { 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");
}

Error Handling

Consumer methods may encounter the following error conditions:

  • Invalid source map format: Malformed source map objects
  • Missing source content: When sourceContentFor is called without nullOnMissing=true
  • Invalid position data: When position objects have invalid line/column values
try {
  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");
}

docs

bundle-building.md

composition.md

consumption.md

function-maps.md

generation.md

index.md

utilities.md

tile.json