0
# Regular Expression Utilities
1
2
Pattern matching utilities for creating precise RegExp patterns, commonly used in plugin hook filters and string matching operations. These functions automatically escape special characters and provide consistent anchoring behavior.
3
4
## Capabilities
5
6
### exactRegex
7
8
Creates a RegExp that matches strings exactly by anchoring at both the beginning and end of the string.
9
10
```typescript { .api }
11
/**
12
* Constructs a RegExp that matches the exact string specified
13
* Automatically escapes special regex characters and anchors with ^ and $
14
* @param str - The string(s) to match exactly
15
* @param flags - Optional RegExp flags (e.g., 'i', 'g', 'm')
16
* @returns RegExp with exact matching (^pattern$)
17
*/
18
function exactRegex(str: string | string[], flags?: string): RegExp;
19
```
20
21
**Parameters:**
22
23
- `str` (string | string[]): The string or array of strings to match exactly. Special regex characters are automatically escaped.
24
- `flags` (string, optional): Standard RegExp flags like `'i'` (case-insensitive), `'g'` (global), `'m'` (multiline)
25
26
**Returns:** RegExp with `^` and `$` anchors for exact matching
27
28
**Usage Examples:**
29
30
```typescript
31
import { exactRegex } from "@rollup/pluginutils";
32
33
// Basic exact matching
34
exactRegex('foobar'); // /^foobar$/
35
exactRegex('hello world'); // /^hello world$/
36
37
// Multiple alternatives
38
exactRegex(['foo', 'bar']); // /^(?:foo|bar)$/
39
exactRegex(['index.js', 'main.js']); // /^(?:index\.js|main\.js)$/
40
41
// With flags
42
exactRegex('FooBar', 'i'); // /^FooBar$/i (case-insensitive)
43
44
// Automatic escaping of special characters
45
exactRegex('foo(bar)'); // /^foo\(bar\)$/
46
exactRegex('app.config.js'); // /^app\.config\.js$/
47
exactRegex('$special^chars'); // /^\$special\^chars$/
48
49
// Use in plugin hooks
50
export default function myPlugin() {
51
const entryPattern = exactRegex(['index.js', 'main.js', 'app.js']);
52
53
return {
54
buildStart() {
55
// Filter entry files
56
const entries = this.getModuleIds().filter(id =>
57
entryPattern.test(id.split('/').pop())
58
);
59
console.log('Entry files:', entries);
60
}
61
};
62
}
63
64
// Virtual module matching
65
export default function virtualPlugin() {
66
const virtualPattern = exactRegex(['virtual:config', 'virtual:env']);
67
68
return {
69
resolveId(id) {
70
if (virtualPattern.test(id)) {
71
return id;
72
}
73
}
74
};
75
}
76
```
77
78
### prefixRegex
79
80
Creates a RegExp that matches strings with a specific prefix by anchoring only at the beginning of the string.
81
82
```typescript { .api }
83
/**
84
* Constructs a RegExp that matches a value that has the specified prefix
85
* Automatically escapes special regex characters and anchors with ^
86
* @param str - The string(s) to match as prefix
87
* @param flags - Optional RegExp flags (e.g., 'i', 'g', 'm')
88
* @returns RegExp with prefix matching (^pattern)
89
*/
90
function prefixRegex(str: string | string[], flags?: string): RegExp;
91
```
92
93
**Parameters:**
94
95
- `str` (string | string[]): The string or array of strings to match as prefix
96
- `flags` (string, optional): Standard RegExp flags
97
98
**Returns:** RegExp with `^` anchor for prefix matching
99
100
**Usage Examples:**
101
102
```typescript
103
import { prefixRegex } from "@rollup/pluginutils";
104
105
// Basic prefix matching
106
prefixRegex('foo'); // /^foo/
107
prefixRegex('src/'); // /^src\//
108
109
// Multiple prefixes
110
prefixRegex(['src/', 'lib/']); // /^(?:src\/|lib\/)/
111
prefixRegex(['@scope/', 'my-']); // /^(?:@scope\/|my-)/
112
113
// With flags
114
prefixRegex('HTTP', 'i'); // /^HTTP/i
115
116
// Automatic escaping
117
prefixRegex('src/components/'); // /^src\/components\//
118
prefixRegex('@rollup/'); // /^@rollup\//
119
120
// Use for module filtering
121
export default function myPlugin() {
122
const srcPattern = prefixRegex(['src/', 'lib/', 'components/']);
123
124
return {
125
transform(code, id) {
126
// Only transform files in source directories
127
if (srcPattern.test(id)) {
128
return { code: transformCode(code) };
129
}
130
}
131
};
132
}
133
134
// Package scope filtering
135
export default function scopePlugin(options = {}) {
136
const { allowedScopes = ['@mycompany/', '@utils/'] } = options;
137
const scopePattern = prefixRegex(allowedScopes);
138
139
return {
140
resolveId(id) {
141
if (scopePattern.test(id)) {
142
// Allow imports from specified scopes
143
return null; // Continue with normal resolution
144
} else {
145
// Block other scoped packages
146
return false;
147
}
148
}
149
};
150
}
151
152
// Environment-based file matching
153
const devPattern = prefixRegex(['dev/', 'development/']);
154
const prodPattern = prefixRegex(['prod/', 'production/']);
155
156
export default function envPlugin(options = {}) {
157
const { environment = 'production' } = options;
158
const pattern = environment === 'development' ? devPattern : prodPattern;
159
160
return {
161
load(id) {
162
if (pattern.test(id)) {
163
// Load environment-specific files
164
return fs.readFileSync(id, 'utf-8');
165
}
166
}
167
};
168
}
169
```
170
171
### suffixRegex
172
173
Creates a RegExp that matches strings with a specific suffix by anchoring only at the end of the string.
174
175
```typescript { .api }
176
/**
177
* Constructs a RegExp that matches a value that has the specified suffix
178
* Automatically escapes special regex characters and anchors with $
179
* @param str - The string(s) to match as suffix
180
* @param flags - Optional RegExp flags (e.g., 'i', 'g', 'm')
181
* @returns RegExp with suffix matching (pattern$)
182
*/
183
function suffixRegex(str: string | string[], flags?: string): RegExp;
184
```
185
186
**Parameters:**
187
188
- `str` (string | string[]): The string or array of strings to match as suffix
189
- `flags` (string, optional): Standard RegExp flags
190
191
**Returns:** RegExp with `$` anchor for suffix matching
192
193
**Usage Examples:**
194
195
```typescript
196
import { suffixRegex } from "@rollup/pluginutils";
197
198
// Basic suffix matching
199
suffixRegex('.js'); // /\.js$/
200
suffixRegex('.test.js'); // /\.test\.js$/
201
202
// Multiple suffixes
203
suffixRegex(['.js', '.ts']); // /(?:\.js|\.ts)$/
204
suffixRegex(['.worker.js', '.worker.ts']); // /(?:\.worker\.js|\.worker\.ts)$/
205
206
// With flags
207
suffixRegex('.JS', 'i'); // /\.JS$/i
208
209
// Automatic escaping
210
suffixRegex('.d.ts'); // /\.d\.ts$/
211
suffixRegex('.(test|spec).js'); // /\.\(test\|spec\)\.js$/
212
213
// File extension filtering
214
export default function myPlugin() {
215
const jsPattern = suffixRegex(['.js', '.jsx', '.ts', '.tsx']);
216
const testPattern = suffixRegex(['.test.js', '.spec.js', '.test.ts', '.spec.ts']);
217
218
return {
219
transform(code, id) {
220
// Only transform JavaScript files
221
if (jsPattern.test(id) && !testPattern.test(id)) {
222
return { code: transformCode(code) };
223
}
224
}
225
};
226
}
227
228
// Worker file detection
229
export default function workerPlugin() {
230
const workerPattern = suffixRegex(['.worker.js', '.worker.ts']);
231
232
return {
233
load(id) {
234
if (workerPattern.test(id)) {
235
// Special handling for worker files
236
return `
237
const workerCode = ${JSON.stringify(fs.readFileSync(id, 'utf-8'))};
238
export default () => new Worker(URL.createObjectURL(
239
new Blob([workerCode], { type: 'application/javascript' })
240
));
241
`;
242
}
243
}
244
};
245
}
246
247
// Asset file handling
248
export default function assetPlugin() {
249
const imagePattern = suffixRegex(['.png', '.jpg', '.jpeg', '.gif', '.svg']);
250
const fontPattern = suffixRegex(['.woff', '.woff2', '.ttf', '.eot']);
251
252
return {
253
load(id) {
254
if (imagePattern.test(id)) {
255
// Emit image as asset
256
const referenceId = this.emitFile({
257
type: 'asset',
258
name: path.basename(id),
259
source: fs.readFileSync(id)
260
});
261
262
return `export default import.meta.ROLLUP_FILE_URL_${referenceId};`;
263
}
264
265
if (fontPattern.test(id)) {
266
// Handle font files
267
return handleFontFile(id);
268
}
269
}
270
};
271
}
272
```
273
274
## Common Patterns
275
276
### Plugin Hook Filters
277
278
```typescript
279
import { exactRegex, prefixRegex, suffixRegex } from "@rollup/pluginutils";
280
281
export default function comprehensivePlugin(options = {}) {
282
const {
283
entryFiles = ['index.js', 'main.js'],
284
sourceDirectories = ['src/', 'lib/'],
285
fileExtensions = ['.js', '.ts', '.jsx', '.tsx'],
286
excludePatterns = ['.test.', '.spec.', '.stories.']
287
} = options;
288
289
// Create patterns
290
const entryPattern = exactRegex(entryFiles);
291
const sourcePattern = prefixRegex(sourceDirectories);
292
const extensionPattern = suffixRegex(fileExtensions);
293
const excludePattern = new RegExp(excludePatterns.map(p =>
294
p.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
295
).join('|'));
296
297
return {
298
buildStart() {
299
console.log('Entry pattern:', entryPattern);
300
console.log('Source pattern:', sourcePattern);
301
console.log('Extension pattern:', extensionPattern);
302
},
303
304
transform(code, id) {
305
const fileName = path.basename(id);
306
const isEntry = entryPattern.test(fileName);
307
const isSource = sourcePattern.test(id);
308
const hasValidExtension = extensionPattern.test(id);
309
const isExcluded = excludePattern.test(id);
310
311
if (hasValidExtension && (isEntry || isSource) && !isExcluded) {
312
return { code: transformCode(code, { isEntry }) };
313
}
314
}
315
};
316
}
317
```
318
319
### Virtual Module Router
320
321
```typescript
322
import { exactRegex, prefixRegex } from "@rollup/pluginutils";
323
324
export default function virtualModulePlugin() {
325
const exactVirtualPattern = exactRegex([
326
'virtual:config',
327
'virtual:env',
328
'virtual:version'
329
]);
330
331
const prefixVirtualPattern = prefixRegex(['virtual:generated-']);
332
333
return {
334
resolveId(id) {
335
if (exactVirtualPattern.test(id) || prefixVirtualPattern.test(id)) {
336
return id;
337
}
338
},
339
340
load(id) {
341
// Handle exact virtual modules
342
if (exactVirtualPattern.test(id)) {
343
switch (id) {
344
case 'virtual:config':
345
return 'export default { apiUrl: "https://api.example.com" };';
346
case 'virtual:env':
347
return `export const NODE_ENV = "${process.env.NODE_ENV}";`;
348
case 'virtual:version':
349
return `export const version = "${packageJson.version}";`;
350
}
351
}
352
353
// Handle prefixed virtual modules
354
if (prefixVirtualPattern.test(id)) {
355
const type = id.replace('virtual:generated-', '');
356
return generateVirtualModule(type);
357
}
358
}
359
};
360
}
361
```
362
363
### File Type Router
364
365
```typescript
366
import { suffixRegex } from "@rollup/pluginutils";
367
368
export default function fileTypePlugin() {
369
const patterns = {
370
scripts: suffixRegex(['.js', '.ts', '.jsx', '.tsx']),
371
styles: suffixRegex(['.css', '.scss', '.sass', '.less']),
372
images: suffixRegex(['.png', '.jpg', '.jpeg', '.gif', '.svg']),
373
fonts: suffixRegex(['.woff', '.woff2', '.ttf', '.eot']),
374
data: suffixRegex(['.json', '.yaml', '.yml', '.xml'])
375
};
376
377
return {
378
load(id) {
379
if (patterns.scripts.test(id)) {
380
return handleScriptFile(id);
381
}
382
383
if (patterns.styles.test(id)) {
384
return handleStyleFile(id);
385
}
386
387
if (patterns.images.test(id)) {
388
return handleImageFile(id);
389
}
390
391
if (patterns.fonts.test(id)) {
392
return handleFontFile(id);
393
}
394
395
if (patterns.data.test(id)) {
396
return handleDataFile(id);
397
}
398
}
399
};
400
}
401
```