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

ignore-list.mddocs/

Google Ignore List Processing

Processing of Google's ignore list extension for source maps, used to mark generated or third-party code that should be ignored during debugging.

Capabilities

GoogleIgnoreListConsumer Class

Processes x_google_ignoreList metadata from source maps to identify sources that should be ignored during debugging and error reporting.

/**
 * Consumes Google ignore list metadata from source maps
 * @param map - Source map object (BasicSourceMap or IndexMap)
 * @param normalizeSourceFn - Optional function to normalize source names
 */
class GoogleIgnoreListConsumer {
  constructor(map: MixedSourceMap, normalizeSourceFn?: SourceNameNormalizer);
  
  /**
   * Checks if a source is in the ignore list
   * @param {source} - Object containing source file name to check (can be null)
   * @returns true if source should be ignored, false otherwise
   */
  isIgnored({source}: {source: ?string}): boolean;
  
  /**
   * Returns this map's ignore list as a new array with indices based on sources
   * @param sources - Array of source names
   * @returns Array of indices representing ignored sources
   */
  toArray(sources: Array<?string>): Array<number>;
}

Usage Examples:

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

// Load source map with ignore list
const sourceMap = JSON.parse(fs.readFileSync('bundle.js.map', 'utf8'));
const ignoreListConsumer = new GoogleIgnoreListConsumer(sourceMap);

// Check if sources should be ignored
const shouldIgnore = ignoreListConsumer.isIgnored({source: 'node_modules/react/index.js'});
if (shouldIgnore) {
  console.log('Source is in ignore list - skip in stack traces');
}

// Filter stack traces to exclude ignored sources
const filterStackTrace = (trace, ignoreConsumer) => {
  return trace
    .split('\n')
    .filter(line => {
      const match = line.match(/at .* \((.*?):\d+:\d+\)/);
      if (match) {
        const source = match[1];
        return !ignoreConsumer.isIgnored({source});
      }
      return true;
    })
    .join('\n');
};

Ignore List Integration

Seamlessly integrates with debugging tools and stack trace processing to hide generated or third-party code.

Common Use Cases:

  1. Library Code Filtering: Hide third-party dependencies from stack traces
  2. Generated Code Filtering: Exclude bundler-generated code and polyfills
  3. Debug Experience: Focus on application code during debugging
// Example: Enhanced stack trace symbolication with ignore list filtering
const Symbolication = require('metro-symbolicate/private/Symbolication');
const GoogleIgnoreListConsumer = require('metro-symbolicate/private/GoogleIgnoreListConsumer');
const { SourceMapConsumer } = require('source-map');

const processStackTraceWithFiltering = (sourceMapContent, stackTrace) => {
  // Create symbolication context
  const context = Symbolication.createContext(SourceMapConsumer, sourceMapContent);
  
  // Create ignore list consumer
  const sourceMap = JSON.parse(sourceMapContent);
  const ignoreList = new GoogleIgnoreListConsumer(sourceMap);
  
  // Symbolicate the stack trace
  const symbolicatedTrace = context.symbolicate(stackTrace);
  
  // Filter out ignored sources
  const filteredTrace = symbolicatedTrace
    .split('\n')
    .filter(line => {
      const match = line.match(/at .* \((.*?):\d+:\d+\)/);
      if (match) {
        const source = match[1];
        return !ignoreList.isIgnored({source});
      }
      return true; // Keep non-source lines (error messages, etc.)
    })
    .join('\n');
  
  return filteredTrace;
};

Source Name Normalization

Handles source name normalization to ensure consistent matching between source maps and ignore lists.

Default Normalization:

Uses the same normalization logic as the source-map@0.5.6 package to ensure consistency:

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

// Default normalization (same as source-map library)
const consumer = new GoogleIgnoreListConsumer(sourceMap);

// Custom normalization for specific bundler configurations
const customConsumer = new GoogleIgnoreListConsumer(sourceMap, (source, options) => {
  // Remove webpack-specific prefixes
  if (source.startsWith('webpack:///')) {
    source = source.slice('webpack:///'.length);
  }
  
  // Handle source root
  if (options.sourceRoot && !source.startsWith('/')) {
    source = options.sourceRoot.replace(/\/$/, '') + '/' + source;
  }
  
  return source;
});

Usage Examples:

// Working with different bundler outputs
const createIgnoreListConsumer = (sourceMap, bundlerType) => {
  let normalizer;
  
  switch (bundlerType) {
    case 'webpack':
      normalizer = (source) => source.replace(/^webpack:\/\/\//, '');
      break;
    case 'metro':
      normalizer = (source) => source; // Metro uses standard normalization
      break;
    default:
      normalizer = undefined; // Use default normalization
  }
  
  return new GoogleIgnoreListConsumer(sourceMap, normalizer);
};

Ignore List Format

Understands the standard Google ignore list format used in source maps.

Source Map Ignore List Structure:

// Example source map with ignore list
{
  "version": 3,
  "sources": [
    "src/app.js",           // index 0 - application code
    "src/utils.js",         // index 1 - application code  
    "node_modules/react/index.js",  // index 2 - library code
    "webpack/bootstrap"     // index 3 - generated code
  ],
  "x_google_ignoreList": [2, 3], // Ignore sources at indices 2 and 3
  // ... other source map fields
}

Ignore List Processing:

const consumer = new GoogleIgnoreListConsumer(sourceMap);

// Check specific sources
console.log(consumer.isIgnored({source: 'src/app.js'}));           // false
console.log(consumer.isIgnored({source: 'src/utils.js'}));         // false  
console.log(consumer.isIgnored({source: 'node_modules/react/index.js'})); // true
console.log(consumer.isIgnored({source: 'webpack/bootstrap'}));    // true

// Handle null/undefined sources gracefully
console.log(consumer.isIgnored({source: null}));      // false
console.log(consumer.isIgnored({source: undefined})); // false

Performance Optimization

Efficiently processes ignore lists using internal caching for repeated queries.

// Internal ignore set is built lazily and cached
const consumer = new GoogleIgnoreListConsumer(largeSourceMap);

// First call builds the ignore set
const isIgnored1 = consumer.isIgnored({source: 'some/source.js'});

// Subsequent calls use cached set for fast lookups
const isIgnored2 = consumer.isIgnored({source: 'another/source.js'});
const isIgnored3 = consumer.isIgnored({source: 'third/source.js'});

Error Handling

Gracefully handles missing or malformed ignore list data.

// Missing ignore list - no sources are ignored
const sourceMapWithoutIgnoreList = {
  version: 3,
  sources: ['src/app.js'],
  mappings: '...'
  // No x_google_ignoreList field
};

const consumer = new GoogleIgnoreListConsumer(sourceMapWithoutIgnoreList);
console.log(consumer.isIgnored({source: 'src/app.js'})); // false

// Invalid ignore list indices are handled gracefully
const sourceMapWithInvalidIgnoreList = {
  version: 3,
  sources: ['src/app.js'],
  mappings: '...',
  x_google_ignoreList: [999] // Index out of bounds
};

const invalidConsumer = new GoogleIgnoreListConsumer(sourceMapWithInvalidIgnoreList);
console.log(invalidConsumer.isIgnored({source: 'src/app.js'})); // false

Types

type MixedSourceMap = BasicSourceMap | IndexMap;

type BasicSourceMap = {
  version: number;
  sources: Array<string>;
  names: Array<string>;
  mappings: string;
  file?: string;
  sourceRoot?: string;
  sourcesContent?: Array<?string>;
  x_google_ignoreList?: Array<number>; // Array of source indices to ignore
};

type IndexMap = {
  version: number;
  file?: string;
  sections: Array<IndexMapSection>;
  x_google_ignoreList?: Array<number>; // Array of source indices to ignore
};

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

docs

chrome-devtools.md

cli-interface.md

core-symbolication.md

ignore-list.md

index.md

source-metadata.md

tile.json