or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-pirates

Properly hijack require, i.e., properly define require hooks and customizations

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/pirates@4.0.x

To install, run

npx @tessl/cli install tessl/npm-pirates@4.0.0

index.mddocs/

Pirates

Pirates is a Node.js library that provides functionality to properly hijack the CommonJS require() process, allowing multiple require hooks to coexist without interfering with each other. It solves compatibility issues between tools like Babel and Istanbul by providing a clean API for implementing custom require transformations.

Package Information

  • Package Name: pirates
  • Package Type: npm
  • Language: JavaScript with TypeScript definitions
  • Installation: npm install pirates

Core Imports

const { addHook } = require('pirates');

For ES modules:

import { addHook } from 'pirates';

Basic Usage

const { addHook } = require('pirates');

// Create a simple transformation hook
const revert = addHook((code, filename) => {
  // Transform the code before it's executed
  return code.replace('@@placeholder', 'console.log("transformed!");');
}, {
  exts: ['.js'], // Only process .js files
  ignoreNodeModules: true // Skip node_modules (default: true)
});

// Later, if you want to remove the hook:
revert();

Architecture

Pirates works by intercepting Node.js's internal Module._extensions mechanism. Key design principles:

  • Non-interfering: Multiple hooks can coexist without breaking each other
  • Reversible: All hooks can be cleanly removed using returned revert functions
  • Flexible: Supports custom file extensions, matcher functions, and selective processing
  • Safe: Built-in validation and error handling prevent broken transformations

Capabilities

Require Hook Registration

The main functionality for adding transformation hooks to the Node.js require process.

/**
 * Add a require hook that transforms code before execution
 * @param hook - Function that receives code and filename, returns transformed code
 * @param opts - Configuration options for the hook
 * @returns Function to revert/remove the hook when called
 */
function addHook(hook: Hook, opts?: Options): RevertFunction;

/**
 * Hook function signature for transforming module code
 * @param code - Source code of the module being required
 * @param filename - Absolute path of the file being processed
 * @returns Transformed code as a string
 */
type Hook = (code: string, filename: string) => string;

/**
 * Function returned by addHook to remove the hook
 */
type RevertFunction = () => void;

Usage Example:

const { addHook } = require('pirates');

const revert = addHook((code, filename) => {
  // Only transform files containing a specific marker
  if (code.includes('// @custom-transform')) {
    return code
      .replace(/var /g, 'let ')
      .replace(/function /g, 'const ');
  }
  return code;
});

// Use your transformed modules...
require('./my-module'); // Will be transformed

// Clean up when done
revert();

Hook Configuration

Comprehensive options for controlling when and how hooks are applied.

interface Options {
  /**
   * File extensions to process (takes precedence over other extension options)
   * @default ['.js']
   */
  extensions?: ReadonlyArray<string> | string;
  
  /**
   * File extensions to process (alias for extensions)
   * @default ['.js']
   */
  exts?: ReadonlyArray<string> | string;
  
  /**
   * File extensions to process (alias for extensions) 
   * @default ['.js']
   */
  extension?: ReadonlyArray<string> | string;
  
  /**
   * File extensions to process (alias for extensions)
   * @default ['.js']
   */
  ext?: ReadonlyArray<string> | string;
  
  /**
   * Custom function to determine which files should be processed
   * @param path - Absolute path of the file being evaluated
   * @returns true to process the file, false to skip it
   */
  matcher?: Matcher | null;
  
  /**
   * Whether to automatically ignore node_modules directories
   * @default true
   */
  ignoreNodeModules?: boolean;
}

/**
 * Custom matcher function for selective file processing
 */
type Matcher = (path: string) => boolean;

Configuration Examples:

const { addHook } = require('pirates');

// Process only TypeScript files
addHook(transformTypeScript, {
  exts: ['.ts', '.tsx']
});

// Use custom file matching logic
addHook(transformSpecialFiles, {
  matcher: (filename) => {
    return filename.includes('.special.') && 
           !filename.includes('.test.');
  }
});

// Process files in node_modules (usually not recommended)
addHook(transformEverything, {
  ignoreNodeModules: false
});

// Multiple extensions with array syntax
addHook(transformJavaScript, {
  extensions: ['.js', '.jsx', '.mjs']
});

Error Handling

Pirates includes built-in validation and clear error messages:

  • Invalid Extensions: Throws TypeError if extension is not a string
  • Invalid Hook Return: Throws Error if hook doesn't return a string
  • Hook Chain Safety: Automatically prevents hook interference and memory leaks
const { addHook } = require('pirates');

// This will throw an error
addHook((code, filename) => {
  // Returning undefined/null breaks the require process
  return null; // Error: Hook returned nothing!
});

// This will throw a TypeError
addHook(myHook, {
  ext: 123 // Error: Invalid Extension: 123
});

Multiple Hook Management

const { addHook } = require('pirates');

// Add multiple hooks that work together
const revertBabel = addHook(babelTransform, { exts: ['.jsx'] });
const revertTypeScript = addHook(tsTransform, { exts: ['.ts'] });
const revertCustom = addHook(customTransform, { 
  matcher: (path) => path.endsWith('.custom.js')
});

// All hooks work independently and can be reverted separately
setTimeout(() => {
  revertBabel(); // Only removes Babel hook
}, 5000);

// Or revert all at once
function cleanup() {
  revertBabel();
  revertTypeScript();
  revertCustom();
}