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

composition.mddocs/

Source Map Composition

Functionality for composing multiple source maps into a single source map, essential for multi-stage transformations in modern JavaScript toolchains.

Capabilities

Source Map Composition

Combine multiple source maps from a transformation pipeline into a single composite source map that maps directly from the final output back to the original source.

/**
 * Composes multiple source maps into a single source map
 * Useful for multi-stage transformations where each stage produces its own source map
 * @param maps - Array of source maps to compose, in transformation order
 * @returns Single composed source map mapping final output to original sources
 */
function composeSourceMaps(maps: Array<MixedSourceMap>): MixedSourceMap;

Usage Examples:

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

// Example: TypeScript -> Babel -> Minifier transformation pipeline
const typeScriptMap = {
  version: 3,
  sources: ["src/app.ts"],
  names: ["greeting"],
  mappings: "AAAA,MAAM,QAAQ,GAAW,YAAY,CAAC",
  sourcesContent: ["const greeting: string = 'hello';"]
};

const babelMap = {
  version: 3,
  sources: ["intermediate.js"],
  names: ["greeting"],
  mappings: "AAAA,IAAM,QAAQ,GAAG,YAAY,CAAC",
  sourcesContent: ["var greeting = 'hello';"]
};

const minifierMap = {
  version: 3,
  sources: ["babel-output.js"],
  names: ["a"],
  mappings: "AAAA,IAAM,CAAC,CAAC,CAAC",
  sourcesContent: ["var a='hello';"]
};

// Compose all transformations into a single map
// Final minified output -> Original TypeScript source
const composedMap = composeSourceMaps([
  typeScriptMap,    // TS -> JS
  babelMap,         // JS -> Babel JS  
  minifierMap       // Babel JS -> Minified
]);

// The composed map now maps directly from minified code to original TypeScript
console.log(composedMap.sources); // ["src/app.ts"]
console.log(composedMap.sourcesContent[0]); // "const greeting: string = 'hello';"

Multi-Stage Transformation

const { composeSourceMaps, Generator } = require("metro-source-map");

// Example: Building a complex transformation pipeline
function createTransformationPipeline(originalCode, stages) {
  const sourceMaps = [];
  let currentCode = originalCode;
  
  // Apply each transformation stage
  stages.forEach((transform, index) => {
    const result = transform(currentCode);
    currentCode = result.code;
    sourceMaps.push(result.map);
  });
  
  // Compose all source maps into one
  const finalMap = composeSourceMaps(sourceMaps);
  
  return {
    code: currentCode,
    map: finalMap
  };
}

// Usage
const pipeline = createTransformationPipeline(originalTypeScript, [
  typeScriptTransform,
  babelTransform,
  minifyTransform
]);

console.log(pipeline.code); // Final transformed code
console.log(pipeline.map.sources[0]); // Original source file

Working with Different Source Map Types

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

// Compose basic and indexed source maps
const basicMap1 = {
  version: 3,
  sources: ["input.js"],
  names: ["fn"],
  mappings: "AAAA,SAAS,EAAE"
};

const indexedMap = {
  version: 3,
  sections: [
    {
      offset: { line: 0, column: 0 },
      map: {
        version: 3,
        sources: ["module1.js"],
        names: ["helper"],
        mappings: "AAAA,SAAS,MAAM"
      }
    }
  ]
};

const basicMap2 = {
  version: 3,
  sources: ["transformed.js"],
  names: ["final"],
  mappings: "AAAA,QAAQ,KAAK"
};

// Compose mixed source map types
const composed = composeSourceMaps([basicMap1, indexedMap, basicMap2]);
// Result will be a source map that traces back to the original sources

Facebook and Hermes Extensions

The composition function preserves Facebook-specific and Hermes-specific extensions when composing source maps.

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

// Source maps with Facebook extensions
const mapWithExtensions = {
  version: 3,
  sources: ["app.js"],
  names: ["main"],
  mappings: "AAAA",
  x_facebook_sources: [
    [{
      names: ["functionA", "functionB"],
      mappings: "AAAA,CAAC"
    }]
  ],
  x_hermes_function_offsets: {
    0: [10, 20, 30]
  },
  x_metro_module_paths: ["src/app.js"]
};

const regularMap = {
  version: 3,
  sources: ["transformed.js"],
  names: ["transformed"],
  mappings: "AAAA"
};

// Compose maps preserving extensions
const composedWithExtensions = composeSourceMaps([
  mapWithExtensions,
  regularMap
]);

// Facebook/Hermes extensions are preserved in the result
console.log(composedWithExtensions.x_facebook_sources);
console.log(composedWithExtensions.x_hermes_function_offsets);

Integration with Bundle Building

const { composeSourceMaps, BundleBuilder } = require("metro-source-map");

// Use composition in bundle building workflows
function buildBundleWithComposition(modules) {
  const builder = new BundleBuilder("bundle.js");
  
  modules.forEach(module => {
    // Each module might have its own transformation chain
    const composedMap = composeSourceMaps(module.transformationMaps);
    builder.append(module.code, composedMap);
  });
  
  return {
    code: builder.getCode(),
    map: builder.getMap()
  };
}

// Usage
const bundle = buildBundleWithComposition([
  {
    code: "var utils = require('./utils');",
    transformationMaps: [tsToJsMap, babelMap]
  },
  {
    code: "var app = require('./app');", 
    transformationMaps: [tsToJsMap, babelMap, minifyMap]
  }
]);

Error Handling

Source map composition may encounter errors in the following cases:

  • Invalid source maps: When input source maps are malformed or have invalid structure
  • Empty input: When the maps array is empty or contains null/undefined values
  • Circular references: When source maps reference each other in circular patterns
const { composeSourceMaps } = require("metro-source-map");

try {
  const composed = composeSourceMaps([validMap1, validMap2]);
} catch (error) {
  if (error.message.includes('Invalid source map')) {
    console.error('One of the input source maps is malformed:', error);
  } else {
    console.error('Source map composition failed:', error);
  }
}

// Safe composition with validation
function safeComposeSourceMaps(maps) {
  const validMaps = maps.filter(map => 
    map && typeof map === 'object' && map.version === 3
  );
  
  if (validMaps.length === 0) {
    return null;
  }
  
  if (validMaps.length === 1) {
    return validMaps[0];
  }
  
  return composeSourceMaps(validMaps);
}

docs

bundle-building.md

composition.md

consumption.md

function-maps.md

generation.md

index.md

utilities.md

tile.json