0
# Utilities
1
2
AST parsing, logging, and debugging utilities for advanced use cases and tool development. Rollup provides several utility functions as separate entry points for specialized scenarios.
3
4
## Capabilities
5
6
### AST Parsing
7
8
Standalone AST parsing utilities that use Rollup's internal parser, available for external tooling and plugin development.
9
10
```typescript { .api }
11
/**
12
* Synchronous AST parsing utility
13
* @param input - JavaScript/TypeScript code to parse
14
* @param options - Parser configuration options
15
* @returns Parsed AST program node
16
*/
17
function parseAst(
18
input: string,
19
options?: {
20
/** Allow return statements outside functions */
21
allowReturnOutsideFunction?: boolean;
22
/** Enable JSX parsing */
23
jsx?: boolean;
24
}
25
): ProgramNode;
26
27
/**
28
* Asynchronous AST parsing utility with cancellation support
29
* @param input - JavaScript/TypeScript code to parse
30
* @param options - Parser configuration options with abort signal
31
* @returns Promise resolving to parsed AST program node
32
*/
33
function parseAstAsync(
34
input: string,
35
options?: {
36
/** Allow return statements outside functions */
37
allowReturnOutsideFunction?: boolean;
38
/** Enable JSX parsing */
39
jsx?: boolean;
40
/** Abort signal for cancellation */
41
signal?: AbortSignal;
42
}
43
): Promise<ProgramNode>;
44
```
45
46
**Usage Examples:**
47
48
```typescript
49
import { parseAst, parseAstAsync } from "rollup/parseAst";
50
51
// Synchronous parsing
52
const code = `
53
import { foo } from './bar.js';
54
export default function main() {
55
return foo();
56
}
57
`;
58
59
const ast = parseAst(code);
60
console.log(ast.type); // 'Program'
61
console.log(ast.body.length); // 2 (import + export)
62
63
// JSX parsing
64
const jsxCode = `
65
function Component() {
66
return <div>Hello World</div>;
67
}
68
`;
69
70
const jsxAst = parseAst(jsxCode, { jsx: true });
71
72
// Asynchronous parsing with cancellation
73
const controller = new AbortController();
74
75
const asyncAst = await parseAstAsync(code, {
76
allowReturnOutsideFunction: true,
77
signal: controller.signal
78
});
79
80
// Cancel parsing if needed
81
// controller.abort();
82
```
83
84
### Log Filtering
85
86
Utility for creating log filtering functions based on filter expressions, useful for custom logging implementations and debugging.
87
88
```typescript { .api }
89
/**
90
* Creates a log filtering function based on filter expressions
91
* @param filters - Array of filter strings
92
* @returns Function that tests whether a log should be included
93
*/
94
function getLogFilter(filters: string[]): (log: RollupLog) => boolean;
95
```
96
97
**Usage Examples:**
98
99
```typescript
100
import { getLogFilter } from "rollup/getLogFilter";
101
102
// Create filter for warnings only
103
const warningsOnly = getLogFilter(['level:warn']);
104
105
// Create filter excluding specific plugins
106
const excludePlugin = getLogFilter(['!plugin:my-plugin']);
107
108
// Complex filtering with multiple conditions
109
const complexFilter = getLogFilter([
110
'level:warn&!code:UNUSED_EXTERNAL_IMPORT',
111
'level:error'
112
]);
113
114
// Usage with custom logging
115
const customLogger = (level, log) => {
116
const filter = getLogFilter(['!plugin:verbose-plugin']);
117
118
if (filter(log)) {
119
console.log(`[${level}] ${log.message}`);
120
}
121
};
122
123
// Filter pattern examples:
124
// 'level:warn' - Only warnings
125
// 'plugin:typescript' - Only from typescript plugin
126
// 'code:CIRCULAR_DEPENDENCY' - Only circular dependency warnings
127
// '!plugin:commonjs' - Exclude commonjs plugin logs
128
// 'level:warn&plugin:typescript' - Warnings from typescript plugin only
129
// 'message:*deprecat*' - Messages containing 'deprecat'
130
```
131
132
### Version Information
133
134
Current version constant for runtime version checking and compatibility verification.
135
136
```typescript { .api }
137
/**
138
* Current Rollup version string
139
*/
140
const VERSION: string;
141
```
142
143
**Usage Examples:**
144
145
```typescript
146
import { VERSION } from "rollup";
147
148
console.log(`Using Rollup ${VERSION}`);
149
150
// Version compatibility checking
151
const requiredVersion = '4.0.0';
152
const currentMajor = parseInt(VERSION.split('.')[0]);
153
const requiredMajor = parseInt(requiredVersion.split('.')[0]);
154
155
if (currentMajor < requiredMajor) {
156
throw new Error(`Requires Rollup ${requiredVersion}+, got ${VERSION}`);
157
}
158
159
// Plugin compatibility
160
const myPlugin = () => ({
161
name: 'my-plugin',
162
buildStart() {
163
console.log(`Plugin initialized with Rollup ${VERSION}`);
164
}
165
});
166
```
167
168
## Advanced Utility Usage
169
170
### Custom AST Processing
171
172
```typescript
173
import { parseAst } from "rollup/parseAst";
174
175
function analyzeImports(code) {
176
const ast = parseAst(code);
177
const imports = [];
178
179
for (const node of ast.body) {
180
if (node.type === 'ImportDeclaration') {
181
imports.push({
182
source: node.source.value,
183
specifiers: node.specifiers.map(spec => ({
184
type: spec.type,
185
imported: spec.imported?.name,
186
local: spec.local.name
187
}))
188
});
189
}
190
}
191
192
return imports;
193
}
194
195
// Usage
196
const code = `
197
import React from 'react';
198
import { useState, useEffect } from 'react';
199
import * as utils from './utils.js';
200
`;
201
202
const imports = analyzeImports(code);
203
console.log(imports);
204
// [
205
// { source: 'react', specifiers: [{ type: 'ImportDefaultSpecifier', local: 'React' }] },
206
// { source: 'react', specifiers: [
207
// { type: 'ImportSpecifier', imported: 'useState', local: 'useState' },
208
// { type: 'ImportSpecifier', imported: 'useEffect', local: 'useEffect' }
209
// ]},
210
// { source: './utils.js', specifiers: [{ type: 'ImportNamespaceSpecifier', local: 'utils' }]}
211
// ]
212
```
213
214
### Sophisticated Log Filtering
215
216
```typescript
217
import { getLogFilter } from "rollup/getLogFilter";
218
219
class LogManager {
220
constructor(filterExpressions = []) {
221
this.filter = getLogFilter(filterExpressions);
222
this.logs = [];
223
}
224
225
handleLog(level, log) {
226
if (this.filter(log)) {
227
const entry = {
228
timestamp: Date.now(),
229
level,
230
...log
231
};
232
233
this.logs.push(entry);
234
this.outputLog(level, entry);
235
}
236
}
237
238
outputLog(level, log) {
239
const color = {
240
warn: '\x1b[33m', // Yellow
241
error: '\x1b[31m', // Red
242
info: '\x1b[36m', // Cyan
243
debug: '\x1b[37m' // White
244
}[level] || '\x1b[0m';
245
246
console.log(`${color}[${level.toUpperCase()}] ${log.message}\x1b[0m`);
247
248
if (log.frame) {
249
console.log(log.frame);
250
}
251
}
252
253
getFilteredLogs(additionalFilters = []) {
254
const filter = getLogFilter(additionalFilters);
255
return this.logs.filter(filter);
256
}
257
258
exportLogs(format = 'json') {
259
switch (format) {
260
case 'json':
261
return JSON.stringify(this.logs, null, 2);
262
case 'csv':
263
return this.logs.map(log =>
264
`${log.timestamp},${log.level},"${log.message}",${log.plugin || ''}"`
265
).join('\n');
266
default:
267
return this.logs;
268
}
269
}
270
}
271
272
// Usage
273
const logManager = new LogManager([
274
'!code:UNUSED_EXTERNAL_IMPORT', // Ignore unused external import warnings
275
'level:warn|level:error' // Only warnings and errors
276
]);
277
278
// In rollup config
279
export default {
280
input: 'src/main.js',
281
output: { file: 'dist/bundle.js', format: 'esm' },
282
onLog: (level, log, defaultHandler) => {
283
logManager.handleLog(level, log);
284
}
285
};
286
```
287
288
### Development Tools Integration
289
290
```typescript
291
import { parseAst, getLogFilter, VERSION } from "rollup";
292
293
class RollupDevTools {
294
constructor() {
295
this.logFilter = getLogFilter(['level:debug']);
296
this.buildStats = {
297
version: VERSION,
298
builds: [],
299
errors: []
300
};
301
}
302
303
analyzeBundleStructure(code) {
304
try {
305
const ast = parseAst(code);
306
return {
307
imports: this.extractImports(ast),
308
exports: this.extractExports(ast),
309
functions: this.extractFunctions(ast),
310
complexity: this.calculateComplexity(ast)
311
};
312
} catch (error) {
313
console.error('AST analysis failed:', error);
314
return null;
315
}
316
}
317
318
extractImports(ast) {
319
return ast.body
320
.filter(node => node.type === 'ImportDeclaration')
321
.map(node => ({
322
source: node.source.value,
323
specifiers: node.specifiers.length,
324
dynamic: false
325
}));
326
}
327
328
extractExports(ast) {
329
return ast.body
330
.filter(node =>
331
node.type === 'ExportDefaultDeclaration' ||
332
node.type === 'ExportNamedDeclaration'
333
)
334
.map(node => ({
335
type: node.type,
336
name: this.getExportName(node)
337
}));
338
}
339
340
extractFunctions(ast) {
341
const functions = [];
342
343
const walk = (node) => {
344
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
345
functions.push({
346
name: node.id?.name || 'anonymous',
347
params: node.params.length,
348
async: node.async,
349
generator: node.generator
350
});
351
}
352
353
// Recursively walk child nodes
354
for (const key in node) {
355
const child = node[key];
356
if (Array.isArray(child)) {
357
child.forEach(walk);
358
} else if (child && typeof child === 'object' && child.type) {
359
walk(child);
360
}
361
}
362
};
363
364
walk(ast);
365
return functions;
366
}
367
368
calculateComplexity(ast) {
369
// Simple complexity calculation based on node types
370
let complexity = 0;
371
372
const walk = (node) => {
373
if (['IfStatement', 'ForStatement', 'WhileStatement', 'SwitchCase'].includes(node.type)) {
374
complexity++;
375
}
376
377
for (const key in node) {
378
const child = node[key];
379
if (Array.isArray(child)) {
380
child.forEach(walk);
381
} else if (child && typeof child === 'object' && child.type) {
382
walk(child);
383
}
384
}
385
};
386
387
walk(ast);
388
return complexity;
389
}
390
391
recordBuild(inputOptions, outputOptions, result) {
392
this.buildStats.builds.push({
393
timestamp: Date.now(),
394
input: inputOptions.input,
395
output: outputOptions.file || outputOptions.dir,
396
format: outputOptions.format,
397
duration: result.duration,
398
size: result.output[0]?.code?.length || 0
399
});
400
}
401
402
generateReport() {
403
return {
404
...this.buildStats,
405
summary: {
406
totalBuilds: this.buildStats.builds.length,
407
totalErrors: this.buildStats.errors.length,
408
averageBuildTime: this.buildStats.builds.reduce((sum, build) =>
409
sum + (build.duration || 0), 0) / this.buildStats.builds.length,
410
formats: [...new Set(this.buildStats.builds.map(b => b.format))]
411
}
412
};
413
}
414
}
415
416
// Usage
417
const devTools = new RollupDevTools();
418
419
export default {
420
input: 'src/main.js',
421
output: { file: 'dist/bundle.js', format: 'esm' },
422
plugins: [{
423
name: 'dev-tools',
424
buildStart(options) {
425
console.log(`Build starting with Rollup ${VERSION}`);
426
},
427
generateBundle(options, bundle) {
428
const mainChunk = Object.values(bundle).find(chunk => chunk.type === 'chunk');
429
if (mainChunk) {
430
const analysis = devTools.analyzeBundleStructure(mainChunk.code);
431
console.log('Bundle analysis:', analysis);
432
}
433
}
434
}]
435
};
436
```
437
438
## Core Types
439
440
```typescript { .api }
441
/**
442
* AST Program node type
443
*/
444
type ProgramNode = RollupAstNode<estree.Program>;
445
446
interface RollupAstNode<T> extends Omit<T, 'loc' | 'range' | 'leadingComments' | 'trailingComments' | 'innerComments' | 'comments'> {
447
start: number;
448
end: number;
449
}
450
451
/**
452
* Error interface extending RollupLog
453
*/
454
interface RollupError extends RollupLog {
455
/** Error name */
456
name?: string;
457
/** Stack trace */
458
stack?: string;
459
/** Files being watched when error occurred */
460
watchFiles?: string[];
461
}
462
463
/**
464
* Log entry interface
465
*/
466
interface RollupLog {
467
/** Log message */
468
message: string;
469
/** Log code identifier */
470
code?: string;
471
/** Related file ID */
472
id?: string;
473
/** Source location */
474
loc?: {
475
column: number;
476
file?: string;
477
line: number;
478
};
479
/** Code frame showing context */
480
frame?: string;
481
/** Related plugin name */
482
plugin?: string;
483
/** Additional metadata */
484
meta?: any;
485
/** Source position */
486
pos?: number;
487
/** URL reference */
488
url?: string;
489
/** Error binding */
490
binding?: string;
491
/** Error cause */
492
cause?: unknown;
493
/** Module exporter */
494
exporter?: string;
495
/** Related module IDs */
496
ids?: string[];
497
/** Export names */
498
names?: string[];
499
/** Plugin-specific code */
500
pluginCode?: unknown;
501
/** Re-exporter module */
502
reexporter?: string;
503
/** Stack trace */
504
stack?: string;
505
}
506
507
/**
508
* Logging function type
509
*/
510
type LoggingFunction = (log: RollupLog | string | (() => RollupLog | string)) => void;
511
512
/**
513
* Log levels
514
*/
515
type LogLevel = 'warn' | 'info' | 'debug';
516
```