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

utilities.mddocs/

Utilities

Additional utility functions for source map manipulation, conversion, and path normalization used throughout the Metro source map ecosystem.

Capabilities

Source Map Conversion

Convert between different source map formats and segment representations.

/**
 * Converts a standard source map object into Babel-compatible segments
 * @param sourceMap - Basic source map object with mappings
 * @returns Array of Babel source map segments for further processing
 */
function toBabelSegments(sourceMap: BasicSourceMap): Array<BabelSourceMapSegment>;

/**
 * Converts a Babel source map segment into Metro's tuple format
 * @param mapping - Babel source map segment object
 * @returns Metro source map segment tuple (2, 4, or 5 elements)
 */
function toSegmentTuple(mapping: BabelSourceMapSegment): MetroSourceMapSegmentTuple;

Usage Examples:

const { toBabelSegments, toSegmentTuple } = require("metro-source-map");

// Convert source map to Babel segments
const sourceMap = {
  version: 3,
  sources: ["app.js"],
  names: ["console", "log"],
  mappings: "AAAA,QAAQ,CAAC,GAAG",
  sourcesContent: ["console.log('hello');"]
};

const babelSegments = toBabelSegments(sourceMap);
console.log(babelSegments);
// [
//   {
//     generated: { line: 1, column: 0 },
//     original: { line: 1, column: 0 },
//     source: "app.js",
//     name: null
//   },
//   {
//     generated: { line: 1, column: 8 },
//     original: { line: 1, column: 8 },
//     source: "app.js", 
//     name: "console"
//   }
// ]

// Convert Babel segment back to Metro tuple
const segment = {
  generated: { line: 1, column: 8 },
  original: { line: 1, column: 8 },
  source: "app.js",
  name: "console"
};

const tuple = toSegmentTuple(segment);
console.log(tuple); // [1, 8, 1, 8, "console"]

Path Normalization

Normalize source paths for consistent source map references across different platforms and environments.

/**
 * Normalizes source file paths for consistent source map references
 * @param source - Source file path to normalize
 * @param sourceRoot - Optional source root directory
 * @returns Normalized source path
 */
function normalizeSourcePath(source: string, sourceRoot?: ?string): string;

Usage Examples:

const { normalizeSourcePath } = require("metro-source-map");

// Basic path normalization
const normalized1 = normalizeSourcePath("./src/app.js");
console.log(normalized1); // "src/app.js"

// With source root
const normalized2 = normalizeSourcePath("../components/Button.js", "/project/src/");
console.log(normalized2); // "components/Button.js"

// Absolute path normalization
const normalized3 = normalizeSourcePath("/home/user/project/src/utils.js", "/home/user/project/");
console.log(normalized3); // "src/utils.js"

// Windows path normalization (when running on Windows)
const normalized4 = normalizeSourcePath("src\\components\\App.js");
console.log(normalized4); // "src/components/App.js"

Segment Type Definitions

Types for working with different source map segment formats.

/**
 * Babel source map segment format
 */
interface BabelSourceMapSegment {
  /** Generated code position */
  generated: {
    line: number;
    column: number;
  };
  /** Original source position (optional) */
  original?: {
    line: number;
    column: number;
  };
  /** Source file path (optional) */
  source?: ?string;
  /** Symbol name (optional) */
  name?: ?string;
}

/**
 * Metro source map segment tuple formats
 */
type MetroSourceMapSegmentTuple =
  | [number, number]                           // Generated position only
  | [number, number, number, number]           // Generated -> Original position
  | [number, number, number, number, string];  // Generated -> Original position + name

Advanced Conversion Usage

const { toBabelSegments, toSegmentTuple, normalizeSourcePath } = require("metro-source-map");

// Process source map with path normalization
function processSourceMapWithNormalizedPaths(sourceMap, sourceRoot) {
  // Convert to Babel segments for processing
  const segments = toBabelSegments(sourceMap);
  
  // Normalize all source paths
  const normalizedSegments = segments.map(segment => ({
    ...segment,
    source: segment.source ? normalizeSourcePath(segment.source, sourceRoot) : segment.source
  }));
  
  // Convert back to Metro tuples
  const tuples = normalizedSegments.map(toSegmentTuple);
  
  return tuples;
}

// Usage
const sourceMap = {
  version: 3,
  sources: ["./src/app.js", "../utils/helper.js"],
  names: ["main", "helper"],
  mappings: "AAAA,SAAS,MAAM,CAAC,CAAC,CAAC"
};

const processedTuples = processSourceMapWithNormalizedPaths(sourceMap, "/project/");
console.log(processedTuples);

Integration with Source Map Generation

const { toSegmentTuple, fromRawMappings, normalizeSourcePath } = require("metro-source-map");

// Convert external source map data to Metro format
function convertExternalSourceMap(externalMap) {
  // External source map might use different segment format
  const externalSegments = externalMap.segments; // Assume some external format
  
  // Convert to Metro tuples
  const metroTuples = externalSegments.map(segment => {
    // Convert external format to Babel format first
    const babelSegment = {
      generated: { line: segment.genLine, column: segment.genCol },
      original: segment.srcLine ? { line: segment.srcLine, column: segment.srcCol } : undefined,
      source: segment.source ? normalizeSourcePath(segment.source) : undefined,
      name: segment.name
    };
    
    // Convert to Metro tuple
    return toSegmentTuple(babelSegment);
  });
  
  return metroTuples;
}

// Use converted tuples in Metro source map generation
function generateFromExternalMap(externalMap, moduleInfo) {
  const metroTuples = convertExternalSourceMap(externalMap);
  
  const modules = [{
    map: metroTuples,
    path: normalizeSourcePath(moduleInfo.path),
    source: moduleInfo.source,
    code: moduleInfo.code,
    isIgnored: false
  }];
  
  return fromRawMappings(modules);
}

Path Normalization Edge Cases

const { normalizeSourcePath } = require("metro-source-map");

// Handle various path formats
const testPaths = [
  "./src/app.js",              // Relative path
  "../components/Button.js",   // Parent directory
  "/absolute/path/file.js",    // Absolute path
  "simple.js",                 // Simple filename
  "src\\windows\\path.js",     // Windows path separators
  "//network/share/file.js",   // Network path
  "C:\\Windows\\file.js",      // Windows absolute
  ""                           // Empty string
];

testPaths.forEach(path => {
  const normalized = normalizeSourcePath(path, "/project/src/");
  console.log(`${path} -> ${normalized}`);
});

// Custom normalization with validation
function safeNormalizeSourcePath(source, sourceRoot) {
  try {
    if (!source || typeof source !== 'string') {
      return source;
    }
    return normalizeSourcePath(source, sourceRoot);
  } catch (error) {
    console.warn(`Path normalization failed for "${source}":`, error);
    return source; // Return original path if normalization fails
  }
}

Error Handling

Utility functions may encounter errors in the following cases:

  • Invalid source maps: When toBabelSegments receives malformed source map data
  • Invalid segments: When toSegmentTuple receives segments with missing required properties
  • Path resolution errors: When normalizeSourcePath cannot resolve complex path structures
const { toBabelSegments, toSegmentTuple, normalizeSourcePath } = require("metro-source-map");

// Safe conversion with error handling
function safeToBabelSegments(sourceMap) {
  try {
    return toBabelSegments(sourceMap);
  } catch (error) {
    console.error('Failed to convert source map to Babel segments:', error);
    return [];
  }
}

function safeToSegmentTuple(segment) {
  try {
    return toSegmentTuple(segment);
  } catch (error) {
    console.warn('Failed to convert segment to tuple:', error);
    // Return a simple generated-only mapping as fallback
    return [segment.generated.line, segment.generated.column];
  }
}

// Robust path normalization
function robustNormalizeSourcePath(source, sourceRoot) {
  if (!source || typeof source !== 'string') {
    return source;
  }
  
  try {
    return normalizeSourcePath(source, sourceRoot);
  } catch (error) {
    // Log the error but don't fail the entire process
    console.debug(`Path normalization warning for "${source}":`, error.message);
    return source;
  }
}

docs

bundle-building.md

composition.md

consumption.md

function-maps.md

generation.md

index.md

utilities.md

tile.json