0
# Code Analysis
1
2
Ice.js provides powerful static analysis utilities for dependency scanning, import analysis, and export discovery in JavaScript/TypeScript projects. These tools enable build optimization, dependency management, and codebase understanding.
3
4
## Capabilities
5
6
### Import Analysis
7
8
Analyze module imports in source files with support for aliases and relative imports.
9
10
```typescript { .api }
11
/**
12
* Analyze module imports in source files
13
* @param files - Array of file paths to analyze
14
* @param options - Analysis configuration options
15
* @returns Promise resolving to Set of imported modules or false on error
16
*/
17
function analyzeImports(files: string[], options: AnalyzeOptions): Promise<Set<string> | false>;
18
19
interface AnalyzeOptions {
20
/** Number of parallel analysis operations (default: 10) */
21
parallel?: number;
22
/** Whether to analyze relative imports (default: false) */
23
analyzeRelativeImport?: boolean;
24
/** Module path aliases for import resolution */
25
alias?: Record<string, string>;
26
}
27
```
28
29
**Usage Examples:**
30
31
```typescript
32
import { analyzeImports } from "@ice/app/analyze";
33
34
// Basic import analysis
35
const sourceFiles = [
36
'src/index.ts',
37
'src/components/App.tsx',
38
'src/utils/helpers.ts'
39
];
40
41
const imports = await analyzeImports(sourceFiles, {
42
parallel: 5,
43
analyzeRelativeImport: true,
44
alias: {
45
'@': './src',
46
'@components': './src/components'
47
}
48
});
49
50
if (imports) {
51
console.log('Discovered imports:', Array.from(imports));
52
// Output: ['react', 'react-dom', 'lodash', './utils/constants', '@/components/Button']
53
}
54
55
// Advanced analysis with custom options
56
const advancedImports = await analyzeImports(['src/**/*.{ts,tsx}'], {
57
parallel: 20,
58
analyzeRelativeImport: false, // Skip relative imports
59
alias: {
60
'@': './src',
61
'@lib': './src/lib',
62
'@components': './src/components',
63
'@utils': './src/utils'
64
}
65
});
66
```
67
68
### Dependency Scanning
69
70
Scan entry points and discover all dependencies including dynamic imports and conditional requires.
71
72
```typescript { .api }
73
/**
74
* Scan entry points and discover dependencies
75
* @param entries - Array of entry point file paths
76
* @param options - Scan configuration options
77
* @returns Promise resolving to dependency scan data
78
*/
79
function scanImports(entries: string[], options?: ScanOptions): Promise<Record<string, DepScanData>>;
80
81
interface ScanOptions {
82
/** Project root directory */
83
rootDir?: string;
84
/** Module path aliases */
85
alias?: Record<string, string>;
86
/** Existing dependency imports to merge with */
87
depImports?: Record<string, DepScanData>;
88
/** ESBuild plugins for custom file processing */
89
plugins?: Plugin[];
90
/** Patterns to exclude from scanning */
91
exclude?: string[];
92
/** Files to ignore during scanning */
93
ignores?: string[];
94
}
95
96
interface DepScanData {
97
/** Imported module specifiers */
98
imports: Set<string>;
99
/** Dynamic import specifiers */
100
dynamicImports: Set<string>;
101
/** Export names from the module */
102
exports: Set<string>;
103
/** File dependencies */
104
deps: Set<string>;
105
/** Whether the module has side effects */
106
hasSideEffects: boolean;
107
}
108
```
109
110
**Usage Examples:**
111
112
```typescript
113
import { scanImports } from "@ice/app/analyze";
114
115
// Basic dependency scanning
116
const entryPoints = ['src/index.ts', 'src/main.tsx'];
117
118
const dependencies = await scanImports(entryPoints, {
119
rootDir: process.cwd(),
120
alias: {
121
'@': './src',
122
'@components': './src/components'
123
},
124
exclude: ['**/*.test.*', '**/*.spec.*'],
125
ignores: ['node_modules', 'dist']
126
});
127
128
// Process scan results
129
Object.entries(dependencies).forEach(([file, data]) => {
130
console.log(`File: ${file}`);
131
console.log(' Imports:', Array.from(data.imports));
132
console.log(' Dynamic imports:', Array.from(data.dynamicImports));
133
console.log(' Exports:', Array.from(data.exports));
134
console.log(' Has side effects:', data.hasSideEffects);
135
});
136
137
// Advanced scanning with custom plugins
138
import { esbuild } from '@ice/bundles';
139
140
const advancedDeps = await scanImports(['src/index.ts'], {
141
rootDir: '/path/to/project',
142
plugins: [
143
{
144
name: 'custom-loader',
145
setup(build) {
146
build.onLoad({ filter: /\.custom$/ }, (args) => {
147
// Custom file processing logic
148
});
149
}
150
}
151
],
152
exclude: ['**/*.md', '**/*.json']
153
});
154
```
155
156
### Export Analysis
157
158
Analyze file exports to understand module interfaces and public APIs.
159
160
```typescript { .api }
161
/**
162
* Get file export information
163
* @param options - File analysis options
164
* @returns Promise resolving to array of export names
165
*/
166
function getFileExports(options: FileExportOptions): Promise<string[]>;
167
168
interface FileExportOptions {
169
/** File path (relative or absolute) */
170
file: string;
171
/** Project root directory */
172
rootDir: string;
173
}
174
```
175
176
**Usage Examples:**
177
178
```typescript
179
import { getFileExports } from "@ice/app/analyze";
180
181
// Analyze exports from a specific file
182
const exports = await getFileExports({
183
file: 'src/utils/helpers.ts',
184
rootDir: process.cwd()
185
});
186
187
console.log('Exported functions:', exports);
188
// Output: ['formatDate', 'validateEmail', 'debounce', 'throttle']
189
190
// Analyze exports from multiple files
191
const files = [
192
'src/components/Button.tsx',
193
'src/components/Input.tsx',
194
'src/hooks/useLocalStorage.ts'
195
];
196
197
const allExports = await Promise.all(
198
files.map(file => getFileExports({
199
file,
200
rootDir: process.cwd()
201
}))
202
);
203
204
files.forEach((file, index) => {
205
console.log(`${file}: [${allExports[index].join(', ')}]`);
206
});
207
```
208
209
### Module Resolution
210
211
Resolve module IDs with alias support for import path resolution.
212
213
```typescript { .api }
214
/**
215
* Resolve module ID with alias support
216
* @param id - Module identifier to resolve
217
* @param alias - Alias configuration with empty values for exclusion
218
* @returns Resolved module path or false if excluded
219
*/
220
function resolveId(id: string, alias: AliasWithEmpty): string | false;
221
222
/**
223
* Get absolute import path with alias resolution
224
* @param id - Module identifier
225
* @param importer - File path of the importing module
226
* @param alias - Alias configuration
227
* @returns Resolved absolute import path
228
*/
229
function getImportPath(id: string, importer: string, alias: Alias): string;
230
231
type Alias = Record<string, string>;
232
type AliasWithEmpty = Record<string, string | false>;
233
```
234
235
**Usage Examples:**
236
237
```typescript
238
import { resolveId, getImportPath } from "@ice/app/analyze";
239
240
// Basic module resolution with aliases
241
const aliasConfig = {
242
'@': './src',
243
'@components': './src/components',
244
'@utils': './src/utils',
245
'excluded-module$': false // Exclude this module
246
};
247
248
// Resolve various import paths
249
console.log(resolveId('@/components/Button', aliasConfig));
250
// Output: './src/components/Button'
251
252
console.log(resolveId('@utils/helpers', aliasConfig));
253
// Output: './src/utils/helpers'
254
255
console.log(resolveId('excluded-module', aliasConfig));
256
// Output: false (excluded)
257
258
// Get absolute import paths
259
const absolutePath = getImportPath(
260
'@/components/Button',
261
'/project/src/pages/Home.tsx',
262
{
263
'@': './src',
264
'@components': './src/components'
265
}
266
);
267
console.log(absolutePath);
268
// Output: '/project/src/components/Button'
269
```
270
271
### Build Optimization Analysis
272
273
Use analysis results for build optimization and bundle splitting.
274
275
```typescript { .api }
276
/**
277
* Analyze codebase for build optimization opportunities
278
*/
279
interface OptimizationAnalysis {
280
/** Unused dependencies that can be removed */
281
unusedDependencies: string[];
282
/** Large dependencies that should be code-split */
283
largeDependencies: Array<{ name: string; size: number }>;
284
/** Circular dependencies that need resolution */
285
circularDependencies: string[][];
286
/** Barrel files that can be optimized */
287
barrelFiles: string[];
288
}
289
```
290
291
**Usage Examples:**
292
293
```typescript
294
import { analyzeImports, scanImports, getFileExports } from "@ice/app/analyze";
295
import fs from 'fs';
296
import path from 'path';
297
298
// Comprehensive analysis for optimization
299
async function analyzeForOptimization(rootDir: string): Promise<OptimizationAnalysis> {
300
// Get all source files
301
const sourceFiles = getAllSourceFiles(rootDir);
302
303
// Analyze imports
304
const imports = await analyzeImports(sourceFiles, {
305
parallel: 10,
306
analyzeRelativeImport: true,
307
alias: {
308
'@': './src'
309
}
310
});
311
312
// Scan dependencies
313
const deps = await scanImports(['src/index.ts'], {
314
rootDir,
315
exclude: ['**/*.test.*']
316
});
317
318
// Find optimization opportunities
319
const analysis: OptimizationAnalysis = {
320
unusedDependencies: findUnusedDependencies(imports, deps),
321
largeDependencies: findLargeDependencies(imports),
322
circularDependencies: findCircularDependencies(deps),
323
barrelFiles: findBarrelFiles(sourceFiles)
324
};
325
326
return analysis;
327
}
328
329
function getAllSourceFiles(rootDir: string): string[] {
330
// Implementation to recursively find all source files
331
// This is a simplified example
332
const glob = require('fast-glob');
333
return glob.sync('src/**/*.{ts,tsx,js,jsx}', { cwd: rootDir });
334
}
335
336
function findUnusedDependencies(imports: Set<string>, deps: any): string[] {
337
// Logic to identify unused dependencies
338
return [];
339
}
340
341
function findLargeDependencies(imports: Set<string>): Array<{ name: string; size: number }> {
342
// Logic to identify large dependencies
343
return [];
344
}
345
346
function findCircularDependencies(deps: any): string[][] {
347
// Logic to detect circular dependencies
348
return [];
349
}
350
351
function findBarrelFiles(files: string[]): string[] {
352
// Logic to identify barrel files (index.ts files that only re-export)
353
return files.filter(file => path.basename(file) === 'index.ts');
354
}
355
```
356
357
### Integration with Build Pipeline
358
359
Integrate analysis tools with custom build pipelines.
360
361
```typescript { .api }
362
/**
363
* Integration example with build pipeline
364
*/
365
interface BuildAnalysisOptions {
366
rootDir: string;
367
entryPoints: string[];
368
alias: Record<string, string>;
369
outputPath: string;
370
}
371
```
372
373
**Usage Examples:**
374
375
```typescript
376
import { analyzeImports, scanImports } from "@ice/app/analyze";
377
import fs from 'fs-extra';
378
379
class BuildAnalyzer {
380
private options: BuildAnalysisOptions;
381
382
constructor(options: BuildAnalysisOptions) {
383
this.options = options;
384
}
385
386
async analyze(): Promise<void> {
387
const { rootDir, entryPoints, alias, outputPath } = this.options;
388
389
// Perform comprehensive analysis
390
const [imports, dependencies] = await Promise.all([
391
this.analyzeAllImports(),
392
this.scanAllDependencies()
393
]);
394
395
// Generate analysis report
396
const report = {
397
timestamp: new Date().toISOString(),
398
rootDir,
399
entryPoints,
400
imports: Array.from(imports || []),
401
dependencies: this.processDependencies(dependencies),
402
statistics: this.calculateStatistics(imports, dependencies)
403
};
404
405
// Save report
406
await fs.writeJson(path.join(outputPath, 'analysis-report.json'), report, {
407
spaces: 2
408
});
409
410
console.log(`Analysis complete. Report saved to ${outputPath}/analysis-report.json`);
411
}
412
413
private async analyzeAllImports(): Promise<Set<string> | false> {
414
const sourceFiles = await this.getAllSourceFiles();
415
416
return analyzeImports(sourceFiles, {
417
parallel: 15,
418
analyzeRelativeImport: true,
419
alias: this.options.alias
420
});
421
}
422
423
private async scanAllDependencies(): Promise<Record<string, DepScanData>> {
424
return scanImports(this.options.entryPoints, {
425
rootDir: this.options.rootDir,
426
alias: this.options.alias,
427
exclude: ['**/*.test.*', '**/*.spec.*', '**/*.stories.*']
428
});
429
}
430
431
private async getAllSourceFiles(): Promise<string[]> {
432
const glob = require('fast-glob');
433
return glob.sync('src/**/*.{ts,tsx,js,jsx}', {
434
cwd: this.options.rootDir
435
});
436
}
437
438
private processDependencies(deps: Record<string, DepScanData>) {
439
return Object.entries(deps).map(([file, data]) => ({
440
file,
441
imports: Array.from(data.imports),
442
dynamicImports: Array.from(data.dynamicImports),
443
exports: Array.from(data.exports),
444
hasSideEffects: data.hasSideEffects
445
}));
446
}
447
448
private calculateStatistics(imports: Set<string> | false, deps: Record<string, DepScanData>) {
449
return {
450
totalImports: imports ? imports.size : 0,
451
totalFiles: Object.keys(deps).length,
452
averageImportsPerFile: imports && Object.keys(deps).length > 0
453
? imports.size / Object.keys(deps).length
454
: 0
455
};
456
}
457
}
458
459
// Usage
460
const analyzer = new BuildAnalyzer({
461
rootDir: process.cwd(),
462
entryPoints: ['src/index.ts', 'src/main.tsx'],
463
alias: {
464
'@': './src',
465
'@components': './src/components',
466
'@utils': './src/utils'
467
},
468
outputPath: './analysis'
469
});
470
471
await analyzer.analyze();
472
```
473
474
These analysis tools provide deep insights into codebase structure, dependencies, and optimization opportunities, enabling data-driven build optimization and better understanding of project architecture.