Properly hijack require, i.e., properly define require hooks and customizations
npx @tessl/cli install tessl/npm-pirates@4.0.00
# Pirates
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: pirates
7
- **Package Type**: npm
8
- **Language**: JavaScript with TypeScript definitions
9
- **Installation**: `npm install pirates`
10
11
## Core Imports
12
13
```javascript
14
const { addHook } = require('pirates');
15
```
16
17
For ES modules:
18
19
```javascript
20
import { addHook } from 'pirates';
21
```
22
23
## Basic Usage
24
25
```javascript
26
const { addHook } = require('pirates');
27
28
// Create a simple transformation hook
29
const revert = addHook((code, filename) => {
30
// Transform the code before it's executed
31
return code.replace('@@placeholder', 'console.log("transformed!");');
32
}, {
33
exts: ['.js'], // Only process .js files
34
ignoreNodeModules: true // Skip node_modules (default: true)
35
});
36
37
// Later, if you want to remove the hook:
38
revert();
39
```
40
41
## Architecture
42
43
Pirates works by intercepting Node.js's internal `Module._extensions` mechanism. Key design principles:
44
45
- **Non-interfering**: Multiple hooks can coexist without breaking each other
46
- **Reversible**: All hooks can be cleanly removed using returned revert functions
47
- **Flexible**: Supports custom file extensions, matcher functions, and selective processing
48
- **Safe**: Built-in validation and error handling prevent broken transformations
49
50
## Capabilities
51
52
### Require Hook Registration
53
54
The main functionality for adding transformation hooks to the Node.js require process.
55
56
```typescript { .api }
57
/**
58
* Add a require hook that transforms code before execution
59
* @param hook - Function that receives code and filename, returns transformed code
60
* @param opts - Configuration options for the hook
61
* @returns Function to revert/remove the hook when called
62
*/
63
function addHook(hook: Hook, opts?: Options): RevertFunction;
64
65
/**
66
* Hook function signature for transforming module code
67
* @param code - Source code of the module being required
68
* @param filename - Absolute path of the file being processed
69
* @returns Transformed code as a string
70
*/
71
type Hook = (code: string, filename: string) => string;
72
73
/**
74
* Function returned by addHook to remove the hook
75
*/
76
type RevertFunction = () => void;
77
```
78
79
**Usage Example:**
80
81
```javascript
82
const { addHook } = require('pirates');
83
84
const revert = addHook((code, filename) => {
85
// Only transform files containing a specific marker
86
if (code.includes('// @custom-transform')) {
87
return code
88
.replace(/var /g, 'let ')
89
.replace(/function /g, 'const ');
90
}
91
return code;
92
});
93
94
// Use your transformed modules...
95
require('./my-module'); // Will be transformed
96
97
// Clean up when done
98
revert();
99
```
100
101
### Hook Configuration
102
103
Comprehensive options for controlling when and how hooks are applied.
104
105
```typescript { .api }
106
interface Options {
107
/**
108
* File extensions to process (takes precedence over other extension options)
109
* @default ['.js']
110
*/
111
extensions?: ReadonlyArray<string> | string;
112
113
/**
114
* File extensions to process (alias for extensions)
115
* @default ['.js']
116
*/
117
exts?: ReadonlyArray<string> | string;
118
119
/**
120
* File extensions to process (alias for extensions)
121
* @default ['.js']
122
*/
123
extension?: ReadonlyArray<string> | string;
124
125
/**
126
* File extensions to process (alias for extensions)
127
* @default ['.js']
128
*/
129
ext?: ReadonlyArray<string> | string;
130
131
/**
132
* Custom function to determine which files should be processed
133
* @param path - Absolute path of the file being evaluated
134
* @returns true to process the file, false to skip it
135
*/
136
matcher?: Matcher | null;
137
138
/**
139
* Whether to automatically ignore node_modules directories
140
* @default true
141
*/
142
ignoreNodeModules?: boolean;
143
}
144
145
/**
146
* Custom matcher function for selective file processing
147
*/
148
type Matcher = (path: string) => boolean;
149
```
150
151
**Configuration Examples:**
152
153
```javascript
154
const { addHook } = require('pirates');
155
156
// Process only TypeScript files
157
addHook(transformTypeScript, {
158
exts: ['.ts', '.tsx']
159
});
160
161
// Use custom file matching logic
162
addHook(transformSpecialFiles, {
163
matcher: (filename) => {
164
return filename.includes('.special.') &&
165
!filename.includes('.test.');
166
}
167
});
168
169
// Process files in node_modules (usually not recommended)
170
addHook(transformEverything, {
171
ignoreNodeModules: false
172
});
173
174
// Multiple extensions with array syntax
175
addHook(transformJavaScript, {
176
extensions: ['.js', '.jsx', '.mjs']
177
});
178
```
179
180
## Error Handling
181
182
Pirates includes built-in validation and clear error messages:
183
184
- **Invalid Extensions**: Throws `TypeError` if extension is not a string
185
- **Invalid Hook Return**: Throws `Error` if hook doesn't return a string
186
- **Hook Chain Safety**: Automatically prevents hook interference and memory leaks
187
188
```javascript
189
const { addHook } = require('pirates');
190
191
// This will throw an error
192
addHook((code, filename) => {
193
// Returning undefined/null breaks the require process
194
return null; // Error: Hook returned nothing!
195
});
196
197
// This will throw a TypeError
198
addHook(myHook, {
199
ext: 123 // Error: Invalid Extension: 123
200
});
201
```
202
203
## Multiple Hook Management
204
205
```javascript
206
const { addHook } = require('pirates');
207
208
// Add multiple hooks that work together
209
const revertBabel = addHook(babelTransform, { exts: ['.jsx'] });
210
const revertTypeScript = addHook(tsTransform, { exts: ['.ts'] });
211
const revertCustom = addHook(customTransform, {
212
matcher: (path) => path.endsWith('.custom.js')
213
});
214
215
// All hooks work independently and can be reverted separately
216
setTimeout(() => {
217
revertBabel(); // Only removes Babel hook
218
}, 5000);
219
220
// Or revert all at once
221
function cleanup() {
222
revertBabel();
223
revertTypeScript();
224
revertCustom();
225
}
226
```