CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-source-map

Generates and consumes source maps for debugging tools that map minified code back to original source code

Pending
Overview
Eval results
Files

source-map-generation.mddocs/

Source Map Generation

The SourceMapGenerator class provides functionality for creating source maps incrementally during code generation. This is ideal for build tools, transpilers, and bundlers that need to track the relationship between generated code and original source files.

Capabilities

SourceMapGenerator Class

Creates source maps incrementally by adding mappings one at a time.

/**
 * Creates a new source map generator
 * @param args - Configuration options for the source map
 */
class SourceMapGenerator {
  constructor(args?: StartOfSourceMap);
  
  /**
   * Creates a new SourceMapGenerator based on a SourceMapConsumer
   * @param sourceMapConsumer - The source map to convert
   */
  static fromSourceMap(sourceMapConsumer: SourceMapConsumer): SourceMapGenerator;
  
  /**
   * Add a single mapping from original source line and column to the generated
   * source's line and column for this source map being created
   * @param mapping - The mapping object containing position information
   */
  addMapping(mapping: Mapping): void;
  
  /**
   * Set the source content for a source file
   * @param sourceFile - The filename of the original source
   * @param sourceContent - The content of the original source file
   */
  setSourceContent(sourceFile: string, sourceContent: string): void;
  
  /**
   * Applies the mappings of a sub-source-map for a specific source file to the
   * source map being generated. Each mapping to the supplied source file is
   * rewritten using the supplied source map.
   * @param sourceMapConsumer - The source map to be applied
   * @param sourceFile - Optional filename of the source file
   * @param sourceMapPath - Optional dirname of the path to the source map
   */
  applySourceMap(
    sourceMapConsumer: SourceMapConsumer,
    sourceFile?: string,
    sourceMapPath?: string
  ): void;
  
  /**
   * Render the source map as a JSON string
   */
  toString(): string;
  
  /**
   * Export the source map as a raw object
   */
  toJSON(): RawSourceMap;
}

interface StartOfSourceMap {
  /** The filename of the generated source */
  file?: string;
  /** A root for all relative URLs in this source map */
  sourceRoot?: string;
  /** Skip validation of mappings */
  skipValidation?: boolean;
}

interface Mapping {
  /** An object with the generated line and column positions */
  generated: Position;
  /** An object with the original line and column positions */
  original: Position;
  /** The original source file (relative to the sourceRoot) */
  source: string;
  /** An optional original token name for this mapping */
  name?: string;
}

interface Position {
  line: number;   // 1-based line number
  column: number; // 0-based column number
}

interface RawSourceMap {
  version: number;
  sources: string[];
  names: string[];
  sourceRoot?: string;
  sourcesContent?: string[];
  mappings: string;
  file: string;
}

Usage Examples:

import { SourceMapGenerator } from "source-map";

// Create a new source map
const map = new SourceMapGenerator({
  file: "bundled.js",
  sourceRoot: "http://example.com/"
});

// Add mappings during code generation
map.addMapping({
  generated: { line: 1, column: 0 },
  source: "input.js",
  original: { line: 1, column: 0 }
});

map.addMapping({
  generated: { line: 1, column: 18 },
  source: "input.js", 
  original: { line: 1, column: 11 },
  name: "add"
});

// Set source content
map.setSourceContent("input.js", "function add(a,b){return a+b}");

// Generate the source map
const sourceMapJSON = map.toString();
console.log(sourceMapJSON);

Constructor Configuration

The SourceMapGenerator constructor accepts an optional configuration object:

interface StartOfSourceMap {
  /** The filename of the generated source */
  file?: string;
  /** A root for all relative URLs in this source map */
  sourceRoot?: string;
  /** Skip validation of mappings */
  skipValidation?: boolean;
}

Usage:

const generator = new SourceMapGenerator({
  file: "output.js",              // Generated file name  
  sourceRoot: "/project/src/",    // Base path for source files
  skipValidation: false           // Enable mapping validation (default)
});

Adding Mappings

Add individual mappings between generated and original positions:

/**
 * Add a single mapping from original source line and column to the generated
 * source's line and column for this source map being created
 */
addMapping(mapping: Mapping): void;

interface Mapping {
  generated: Position;  // Required: position in generated code
  original: Position;   // Required: position in original code
  source: string;       // Required: original source file name
  name?: string;        // Optional: original identifier name
}

Usage:

// Basic mapping
map.addMapping({
  generated: { line: 10, column: 5 },
  original: { line: 20, column: 15 },
  source: "original.js"
});

// Mapping with identifier name
map.addMapping({
  generated: { line: 15, column: 8 },
  original: { line: 25, column: 12 },
  source: "original.js",
  name: "functionName"
});

Source Content Management

Set the content of original source files:

/**
 * Set the source content for a source file
 * @param sourceFile - The filename of the original source
 * @param sourceContent - The content of the original source file
 */
setSourceContent(sourceFile: string, sourceContent: string): void;

Usage:

// Set content for debugging
map.setSourceContent("math.js", `
function add(a, b) {
  return a + b;
}
`);

map.setSourceContent("utils.js", `
export function format(value) {
  return String(value);
}
`);

Applying Sub-Source Maps

Combine multiple source maps when dealing with transpilation chains:

/**
 * Applies the mappings of a sub-source-map for a specific source file
 * @param sourceMapConsumer - The source map to be applied
 * @param sourceFile - Optional filename of the source file
 * @param sourceMapPath - Optional dirname of the path to the source map
 */
applySourceMap(
  sourceMapConsumer: SourceMapConsumer,
  sourceFile?: string,
  sourceMapPath?: string
): void;

Usage:

import { SourceMapConsumer, SourceMapGenerator } from "source-map";

// Apply TypeScript -> JavaScript source map to JavaScript -> minified map
const tsToJsMap = await new SourceMapConsumer(typescriptSourceMap);
const jsToMinMap = new SourceMapGenerator({ file: "output.min.js" });

// This creates a direct TypeScript -> minified mapping
jsToMinMap.applySourceMap(tsToJsMap, "intermediate.js");

Creating from Existing Consumer

Convert a SourceMapConsumer back into a generator:

/**
 * Creates a new SourceMapGenerator based on a SourceMapConsumer
 * @param sourceMapConsumer - The source map to convert
 */
static fromSourceMap(sourceMapConsumer: SourceMapConsumer): SourceMapGenerator;

Usage:

// Load existing source map
const consumer = await new SourceMapConsumer(existingSourceMap);

// Convert to generator for modification
const generator = SourceMapGenerator.fromSourceMap(consumer);

// Add additional mappings
generator.addMapping({
  generated: { line: 100, column: 0 },
  original: { line: 50, column: 10 },
  source: "new-file.js"
});

// Clean up consumer
consumer.destroy();

Serialization

Export the source map in various formats:

/**
 * Render the source map as a JSON string
 */
toString(): string;

/**
 * Export the source map as a raw object
 */
toJSON(): RawSourceMap;

Usage:

// Get as JSON string for embedding
const jsonString = generator.toString();
console.log(jsonString);
// Output: {"version":3,"sources":["input.js"],"names":[],"mappings":"AAAA","file":"output.js"}

// Get as object for manipulation
const mapObject = generator.toJSON();
console.log(mapObject.sources);  // ["input.js"]
console.log(mapObject.version);  // 3

Error Handling

The SourceMapGenerator validates mappings and throws errors for invalid inputs:

  • Line numbers must be >= 1 (1-based indexing)
  • Column numbers must be >= 0 (0-based indexing)
  • Source file names must be provided for mappings with original positions
  • Invalid mapping structure will throw TypeError

Example error handling:

try {
  map.addMapping({
    generated: { line: 0, column: 5 },  // Invalid: line must be >= 1
    original: { line: 1, column: 0 },
    source: "test.js"
  });
} catch (error) {
  console.error("Invalid mapping:", error.message);
}

Install with Tessl CLI

npx tessl i tessl/npm-source-map

docs

index.md

source-map-consumption.md

source-map-generation.md

source-node-building.md

tile.json