CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-webpack-sources

Source code handling classes for webpack and other build tools with optional source map support

Pending
Overview
Eval results
Files

source-manipulation.mddocs/

Source Manipulation

Classes for combining, modifying, and transforming sources while preserving source map information.

Capabilities

ConcatSource

Concatenates multiple sources or strings into a single source, preserving source map information from all components.

/**
 * Concatenates multiple sources or strings
 * @param items - Sources, strings, or source-like objects to concatenate
 */
class ConcatSource extends Source {
  constructor(...items: ConcatSourceChild[]);
  
  /** Adds an item to the end of the concatenated source */
  add(item: ConcatSourceChild): void;
  
  /** Adds multiple items efficiently without optimization checks */
  addAllSkipOptimizing(items: ConcatSourceChild[]): void;
  
  /** Returns array of child sources */
  getChildren(): Source[];
  
  /** Streams chunks from all concatenated sources */
  streamChunks(
    options: StreamChunksOptions,
    onChunk: OnChunk,
    onSource: OnSource,
    onName: OnName
  ): GeneratedSourceInfo;
}

/** Items that can be concatenated */
type ConcatSourceChild = string | Source | SourceLike;

Usage Examples:

const { ConcatSource, RawSource, OriginalSource } = require("webpack-sources");

// Concatenate mixed content
const concat = new ConcatSource(
  "// Header comment\n",
  new OriginalSource("const x = 1;", "module.js"),
  "\n",
  new RawSource("console.log(x);")
);

console.log(concat.source());
// Output:
// // Header comment
// const x = 1;
// console.log(x);

// Add more content dynamically
concat.add("\n// Footer");
concat.add(new RawSource("module.exports = x;"));

// Check children
const children = concat.getChildren();
console.log(children.length); // Number of child sources

// Efficient bulk addition
const moreItems = [
  "\n// More code",
  new RawSource("console.log('done');")
];
concat.addAllSkipOptimizing(moreItems);

ReplaceSource

Decorates a source with replacements and insertions, preserving source map information with identity mappings support.

/**
 * Source with replacements and insertions
 * @param source - The source to decorate with replacements
 * @param name - Optional name for the source
 */
class ReplaceSource extends Source {
  constructor(source: Source, name?: string);
  
  /** 
   * Replaces characters from start to end with replacement text
   * @param start - Start position (0-indexed, inclusive)
   * @param end - End position (0-indexed, inclusive)  
   * @param newValue - Replacement text
   * @param name - Optional name for the replacement
   */
  replace(start: number, end: number, newValue: string, name?: string): void;
  
  /**
   * Inserts text before the specified position
   * @param pos - Position to insert before (0-indexed)
   * @param newValue - Text to insert
   * @param name - Optional name for the insertion
   */
  insert(pos: number, newValue: string, name?: string): void;
  
  /** Returns the original decorated source */
  original(): Source;
  
  /** Returns the name if provided */
  getName(): string | undefined;
  
  /** Returns array of all replacements */
  getReplacements(): Replacement[];
  
  /** Streams chunks with replacement and insertion processing */
  streamChunks(
    options: StreamChunksOptions,
    onChunk: OnChunk,
    onSource: OnSource,
    onName: OnName
  ): GeneratedSourceInfo;
  
  /** Replacement class constructor */
  static Replacement: typeof Replacement;
}

Usage Examples:

const { ReplaceSource, OriginalSource } = require("webpack-sources");

const original = new OriginalSource(
  "function hello(name) {\n  console.log('Hello ' + name);\n}",
  "hello.js"
);

const modified = new ReplaceSource(original, "modified-hello.js");

// Replace function name
modified.replace(9, 13, "greet"); // Replace "hello" with "greet"

// Insert parameter validation
modified.insert(23, "if (!name) return; ");

// Replace string concatenation with template literal
modified.replace(45, 63, "`Hello ${name}`");

console.log(modified.source());
// Output:
// function greet(name) {
//   if (!name) return; console.log(`Hello ${name}`);
// }

console.log(modified.getName()); // "modified-hello.js"
console.log(modified.original() === original); // true

// Get all modifications
const replacements = modified.getReplacements();
console.log(replacements.length); // Number of replacements/insertions

PrefixSource

Prefixes every line of a source with a provided string, useful for indentation or commenting.

/**
 * Prefixes every line with a string
 * @param prefix - String to prefix each line with
 * @param source - Source to prefix (string, Buffer, or Source)
 */
class PrefixSource extends Source {
  constructor(prefix: string, source: string | Source | Buffer);
  
  /** Returns the prefix string */
  getPrefix(): string;
  
  /** Returns the original source */
  original(): Source;
  
  /** Streams chunks with line prefixing */
  streamChunks(
    options: StreamChunksOptions,
    onChunk: OnChunk,
    onSource: OnSource,
    onName: OnName
  ): GeneratedSourceInfo;
}

Usage Examples:

const { PrefixSource, RawSource } = require("webpack-sources");

// Add indentation
const code = "console.log('test');\nconsole.log('done');";
const indented = new PrefixSource("  ", code);

console.log(indented.source());
// Output:
//   console.log('test');
//   console.log('done');

// Add comment prefix
const commented = new PrefixSource("// ", new RawSource(code));
console.log(commented.source());
// Output:
// // console.log('test');
// // console.log('done');

console.log(commented.getPrefix()); // "// "
console.log(commented.original().source()); // Original uncommented code

// Complex prefixing
const numbered = new PrefixSource("/* Line */  ", code);
console.log(numbered.source());
// Output:
// /* Line */  console.log('test');
// /* Line */  console.log('done');

Replacement Class

Represents a single replacement operation in ReplaceSource.

/**
 * Represents a replacement operation
 * @param start - Start position (0-indexed, inclusive)
 * @param end - End position (0-indexed, inclusive)
 * @param content - Replacement content
 * @param name - Optional name for the replacement
 */
class Replacement {
  constructor(start: number, end: number, content: string, name?: string);
  
  /** Start position of replacement */
  start: number;
  
  /** End position of replacement */
  end: number;
  
  /** Replacement content */
  content: string;
  
  /** Optional replacement name */
  name?: string;
  
  /** Optional index for ordering */
  index?: number;
}

Usage Example:

const { ReplaceSource } = require("webpack-sources");

// Access Replacement class
const ReplacementClass = ReplaceSource.Replacement;

// Create replacement manually (usually not needed)
const replacement = new ReplacementClass(0, 4, "const", "var-to-const");
console.log(replacement.start); // 0
console.log(replacement.end); // 4
console.log(replacement.content); // "const"
console.log(replacement.name); // "var-to-const"

Source-Like Interface

Interface for objects that can be used as sources in concatenation and other operations.

/**
 * Interface for source-like objects that can be converted to Sources
 */
interface SourceLike {
  /** Returns source content */
  source(): string | Buffer;
  /** Optional method to return content as Buffer */
  buffer?(): Buffer;
  /** Optional method to return size */
  size?(): number;
  /** Optional method to return source map */
  map?(options?: MapOptions): RawSourceMap | null;
  /** Optional method to return both source and map */
  sourceAndMap?(options?: MapOptions): SourceAndMap;
  /** Optional method to update hash */
  updateHash?(hash: HashLike): void;
}

Install with Tessl CLI

npx tessl i tessl/npm-webpack-sources

docs

base-source.md

caching-performance.md

index.md

source-implementations.md

source-manipulation.md

utility-classes.md

tile.json