migrate-barrel-imports 0.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +5 -465
  2. package/package.json +15 -5
package/dist/index.js CHANGED
@@ -1,466 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import {Command as $cUHbR$Command} from "commander";
3
- import {readFileSync as $cUHbR$readFileSync, writeFileSync as $cUHbR$writeFileSync} from "node:fs";
4
- import $cUHbR$nodepath, {join as $cUHbR$join} from "node:path";
5
- import $cUHbR$babelgenerator from "@babel/generator";
6
- import {parse as $cUHbR$parse} from "@babel/parser";
7
- import $cUHbR$babeltraverse from "@babel/traverse";
8
- import {isVariableDeclaration as $cUHbR$isVariableDeclaration, isIdentifier as $cUHbR$isIdentifier, isExportSpecifier as $cUHbR$isExportSpecifier, isFunctionDeclaration as $cUHbR$isFunctionDeclaration, isImportSpecifier as $cUHbR$isImportSpecifier, importDeclaration as $cUHbR$importDeclaration, importSpecifier as $cUHbR$importSpecifier, stringLiteral as $cUHbR$stringLiteral} from "@babel/types";
9
- import $cUHbR$fastglob from "fast-glob";
10
- import $cUHbR$micromatch from "micromatch";
11
-
12
-
13
- /**
14
- * @fileoverview Tool for migrating TypeScript projects from barrel file exports to direct file imports
15
- *
16
- * This tool helps migrate TypeScript projects that use barrel files (index.ts files that re-export)
17
- * to use direct imports from source files instead. This improves:
18
- * - Tree-shaking efficiency
19
- * - Build performance
20
- * - Code maintainability
21
- * - TypeScript compilation speed
22
- *
23
- * The migration process:
24
- * 1. Scans source package for all exports
25
- * 2. Finds all files importing from the package
26
- * 3. Updates imports to point directly to source files
27
- * 4. Preserves original import names and types
28
- */
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
- /**
37
- * Reads and parses the package.json file for a given package path
38
- *
39
- * @param {string} packagePath - The path to the package directory
40
- * @returns {Promise<PackageJson>} The parsed package.json contents
41
- * @throws {Error} If package.json cannot be read or parsed
42
- */ async function $1d95f64f52ade133$var$getPackageInfo(packagePath) {
43
- const packageJsonPath = (0, $cUHbR$join)(packagePath, 'package.json');
44
- const content = (0, $cUHbR$readFileSync)(packageJsonPath, 'utf-8');
45
- return JSON.parse(content);
46
- }
47
- /**
48
- * Recursively finds all exports in a package by scanning all TypeScript files
49
- *
50
- * This function:
51
- * 1. Scans all .ts and .tsx files in the package
52
- * 2. Identifies both named exports and default exports
53
- * 3. Skips re-exports to avoid circular dependencies
54
- * 4. Filters out ignored files based on patterns
55
- *
56
- * @param {FindExportsParams} params - Parameters for finding exports
57
- * @returns {Promise<ExportInfo[]>} Array of export information, including source file and exported names
58
- */ async function $1d95f64f52ade133$var$findExports({ packagePath: packagePath, ignoreSourceFiles: ignoreSourceFiles = [], stats: stats }) {
59
- const exports = [];
60
- console.log(`Scanning for TypeScript files in: ${packagePath}`);
61
- const allFiles = await (0, $cUHbR$fastglob)('**/*.{ts,tsx}', {
62
- cwd: packagePath,
63
- ignore: [
64
- '**/node_modules/**',
65
- '**/dist/**',
66
- '**/build/**'
67
- ]
68
- });
69
- console.log(`Found ${allFiles.length} TypeScript files`);
70
- for (const file of allFiles){
71
- // Mark files that match ignore patterns but still process them
72
- const isIgnored = ignoreSourceFiles.some((pattern)=>(0, $cUHbR$micromatch).isMatch(file, pattern));
73
- if (isIgnored) {
74
- console.log(`File matches ignore pattern but will be preserved: ${file}`);
75
- if (stats) stats.sourceFilesSkipped++;
76
- }
77
- const fullPath = (0, $cUHbR$join)(packagePath, file);
78
- console.log(`\nProcessing file: ${file}`);
79
- const content = (0, $cUHbR$readFileSync)(fullPath, 'utf-8');
80
- try {
81
- const ast = (0, $cUHbR$parse)(content, {
82
- sourceType: 'module',
83
- plugins: [
84
- 'typescript',
85
- 'jsx',
86
- 'decorators-legacy',
87
- 'classProperties',
88
- 'classPrivateProperties',
89
- 'classPrivateMethods',
90
- 'exportDefaultFrom',
91
- 'exportNamespaceFrom',
92
- 'functionBind',
93
- 'functionSent',
94
- 'dynamicImport',
95
- 'nullishCoalescingOperator',
96
- 'optionalChaining',
97
- 'objectRestSpread',
98
- 'asyncGenerators',
99
- 'doExpressions',
100
- 'importMeta',
101
- 'logicalAssignment',
102
- 'moduleBlocks',
103
- 'moduleStringNames',
104
- 'numericSeparator',
105
- 'partialApplication',
106
- 'privateIn',
107
- 'throwExpressions',
108
- 'topLevelAwait'
109
- ]
110
- });
111
- (0, $cUHbR$babeltraverse)(ast, {
112
- ExportNamedDeclaration (path) {
113
- console.log(`Found named export in ${file}`);
114
- // Skip exports from other files (we only want direct exports)
115
- if (path.node.source) {
116
- console.log(`Skipping re-export from ${path.node.source.value}`);
117
- return;
118
- }
119
- // Handle variable declarations with exports
120
- if (path.node.declaration) {
121
- if ($cUHbR$isVariableDeclaration(path.node.declaration)) {
122
- const declarations = path.node.declaration.declarations;
123
- const namedExports = declarations.map((d)=>{
124
- if ($cUHbR$isIdentifier(d.id)) return d.id.name;
125
- return null;
126
- }).filter((name)=>name !== null);
127
- if (namedExports.length > 0) {
128
- console.log(`Named exports found: ${namedExports.join(', ')}`);
129
- exports.push({
130
- source: file,
131
- exports: namedExports,
132
- isIgnored: isIgnored
133
- });
134
- }
135
- }
136
- return;
137
- }
138
- // Handle export specifiers
139
- const namedExports = path.node.specifiers.map((s)=>{
140
- if ($cUHbR$isExportSpecifier(s)) {
141
- const exported = s.exported;
142
- return $cUHbR$isIdentifier(exported) ? exported.name : exported.value;
143
- }
144
- return null;
145
- }).filter((name)=>name !== null);
146
- if (namedExports.length > 0) {
147
- console.log(`Named exports found: ${namedExports.join(', ')}`);
148
- exports.push({
149
- source: file,
150
- exports: namedExports,
151
- isIgnored: isIgnored
152
- });
153
- }
154
- },
155
- ExportDefaultDeclaration (path) {
156
- console.log(`Found default export in ${file}`);
157
- const exported = path.node.declaration;
158
- if ($cUHbR$isIdentifier(exported)) {
159
- console.log(`Default export name: ${exported.name}`);
160
- exports.push({
161
- source: file,
162
- exports: [
163
- exported.name
164
- ],
165
- isIgnored: isIgnored
166
- });
167
- } else if ($cUHbR$isFunctionDeclaration(exported) && exported.id) {
168
- console.log(`Default export name: ${exported.id.name}`);
169
- exports.push({
170
- source: file,
171
- exports: [
172
- exported.id.name
173
- ],
174
- isIgnored: isIgnored
175
- });
176
- } else console.log('Default export is not an identifier or named function');
177
- }
178
- });
179
- } catch (error) {
180
- console.error(`Error parsing ${file}:`, error);
181
- }
182
- }
183
- console.log(`\nTotal exports found: ${exports.length}`);
184
- return exports;
185
- }
186
- /**
187
- * Finds all files in the monorepo that import from a specific package
188
- *
189
- * This function:
190
- * 1. Uses fast-glob to find all TypeScript files
191
- * 2. Parses each file's AST to find imports
192
- * 3. Handles both direct package imports and subpath imports
193
- * 4. Excludes node_modules, dist, and build directories
194
- *
195
- * @param {FindImportsParams} params - Parameters for finding imports
196
- * @returns {Promise<string[]>} Array of file paths that import from the package
197
- */ async function $1d95f64f52ade133$var$findImports({ packageName: packageName, monorepoRoot: monorepoRoot }) {
198
- try {
199
- const allFiles = new Set();
200
- // Find all TypeScript files in the monorepo
201
- const files = await (0, $cUHbR$fastglob)([
202
- '**/*.{ts,tsx}'
203
- ], {
204
- cwd: monorepoRoot,
205
- absolute: true,
206
- ignore: [
207
- '**/node_modules/**',
208
- '**/dist/**',
209
- '**/build/**'
210
- ],
211
- followSymbolicLinks: false
212
- });
213
- console.log(`Found ${files.length} TypeScript files to scan`);
214
- // Scan each file for imports
215
- for (const file of files)try {
216
- const content = (0, $cUHbR$readFileSync)(file, 'utf-8');
217
- const ast = (0, $cUHbR$parse)(content, {
218
- sourceType: 'module',
219
- plugins: [
220
- 'typescript',
221
- 'jsx'
222
- ]
223
- });
224
- (0, $cUHbR$babeltraverse)(ast, {
225
- ImportDeclaration (path) {
226
- const source = path.node.source.value;
227
- // Check for exact package import or subpath import
228
- if (source === packageName || source.startsWith(`${packageName}/`)) allFiles.add(file);
229
- }
230
- });
231
- } catch (error) {
232
- console.error(`Error processing file ${file}:`, error);
233
- }
234
- const uniqueFiles = Array.from(allFiles);
235
- if (uniqueFiles.length > 0) {
236
- console.log(`Found total of ${uniqueFiles.length} files with imports from ${packageName}`);
237
- console.log('Files found:');
238
- for (const file of uniqueFiles)console.log(` ${file}`);
239
- } else console.log(`No files found importing from ${packageName}`);
240
- return uniqueFiles;
241
- } catch (error) {
242
- console.error('Error finding imports:', error);
243
- return [];
244
- }
245
- }
246
- /**
247
- * Updates imports in a file to point directly to source files instead of using barrel files
248
- *
249
- * This function:
250
- * 1. Parses the file's AST to find imports from the package
251
- * 2. For each import, finds the source file containing the export
252
- * 3. Updates the import to point directly to the source file
253
- * 4. Preserves original import names and types
254
- * 5. Only modifies the file if changes are needed
255
- *
256
- * @param {UpdateImportsParams} params - Parameters for updating imports
257
- * @returns {Promise<void>}
258
- */ async function $1d95f64f52ade133$var$updateImports({ filePath: filePath, packageName: packageName, exports: exports, includeExtension: includeExtension = true }) {
259
- console.log(`\nProcessing file: ${filePath}`);
260
- const content = (0, $cUHbR$readFileSync)(filePath, 'utf-8');
261
- try {
262
- const ast = (0, $cUHbR$parse)(content, {
263
- sourceType: 'module',
264
- plugins: [
265
- 'typescript',
266
- 'jsx',
267
- 'decorators-legacy',
268
- 'classProperties',
269
- 'classPrivateProperties',
270
- 'classPrivateMethods',
271
- 'exportDefaultFrom',
272
- 'exportNamespaceFrom',
273
- 'functionBind',
274
- 'functionSent',
275
- 'dynamicImport',
276
- 'nullishCoalescingOperator',
277
- 'optionalChaining',
278
- 'objectRestSpread',
279
- 'asyncGenerators',
280
- 'doExpressions',
281
- 'importMeta',
282
- 'logicalAssignment',
283
- 'moduleBlocks',
284
- 'moduleStringNames',
285
- 'numericSeparator',
286
- 'partialApplication',
287
- 'privateIn',
288
- 'throwExpressions',
289
- 'topLevelAwait'
290
- ]
291
- });
292
- let modified = false;
293
- let importCount = 0;
294
- (0, $cUHbR$babeltraverse)(ast, {
295
- ImportDeclaration (path) {
296
- if (path.node.source.value === packageName) {
297
- importCount++;
298
- console.log(`Found import from ${packageName}`);
299
- const specifiers = path.node.specifiers;
300
- const newImports = [];
301
- for (const specifier of specifiers)if ($cUHbR$isImportSpecifier(specifier)) {
302
- const imported = specifier.imported;
303
- const importName = $cUHbR$isIdentifier(imported) ? imported.name : imported.value;
304
- const exportInfo = exports.find((e)=>e.exports.includes(importName));
305
- if (exportInfo) {
306
- console.log(` Found export ${importName} in ${exportInfo.source}`);
307
- // Skip modifying imports from ignored files
308
- if (exportInfo.isIgnored) {
309
- console.log(` Keeping original import for ignored file: ${exportInfo.source}`);
310
- continue;
311
- }
312
- const importPath = includeExtension ? `${packageName}/${exportInfo.source}` : `${packageName}/${exportInfo.source.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/, '')}`;
313
- newImports.push($cUHbR$importDeclaration([
314
- $cUHbR$importSpecifier(specifier.local, specifier.imported)
315
- ], $cUHbR$stringLiteral(importPath)));
316
- modified = true;
317
- } else console.log(` Warning: Could not find export ${importName}`);
318
- }
319
- if (newImports.length > 0) {
320
- // If there are any remaining specifiers that weren't moved to direct imports,
321
- // create a new import declaration for them
322
- const remainingSpecifiers = specifiers.filter((s)=>{
323
- if (!$cUHbR$isImportSpecifier(s)) return true;
324
- const importName = $cUHbR$isIdentifier(s.imported) ? s.imported.name : s.imported.value;
325
- const exportInfo = exports.find((e)=>e.exports.includes(importName));
326
- return !exportInfo || exportInfo.isIgnored;
327
- });
328
- if (remainingSpecifiers.length > 0) newImports.unshift($cUHbR$importDeclaration(remainingSpecifiers, $cUHbR$stringLiteral(packageName)));
329
- path.replaceWithMultiple(newImports);
330
- console.log(' Replaced import with direct imports from source files');
331
- }
332
- }
333
- }
334
- });
335
- if (modified) {
336
- console.log(`Writing changes to ${filePath}`);
337
- const output = (0, $cUHbR$babelgenerator)(ast, {
338
- retainLines: false,
339
- retainFunctionParens: true
340
- }, content);
341
- (0, $cUHbR$writeFileSync)(filePath, output.code);
342
- } else if (importCount > 0) console.log(`No changes needed for ${importCount} imports`);
343
- else console.log('No imports found to update');
344
- } catch (error) {
345
- console.error(`Error processing ${filePath}:`, error);
346
- }
347
- }
348
- async function $1d95f64f52ade133$export$eb4d0c836e660010(options) {
349
- const { sourcePath: sourcePath, targetPath: targetPath, ignoreSourceFiles: ignoreSourceFiles, ignoreTargetFiles: ignoreTargetFiles } = options;
350
- // Track migration statistics
351
- const stats = {
352
- totalFiles: 0,
353
- filesProcessed: 0,
354
- filesSkipped: 0,
355
- importsUpdated: 0,
356
- filesWithNoUpdates: 0,
357
- errors: 0,
358
- totalExports: 0,
359
- sourceFilesScanned: 0,
360
- sourceFilesWithExports: 0,
361
- sourceFilesSkipped: 0,
362
- targetFilesFound: []
363
- };
364
- const packageInfo = await $1d95f64f52ade133$var$getPackageInfo(sourcePath);
365
- const exports = await $1d95f64f52ade133$var$findExports({
366
- packagePath: sourcePath,
367
- ignoreSourceFiles: ignoreSourceFiles,
368
- stats: stats
369
- });
370
- // Calculate total number of unique exports and source files
371
- stats.totalExports = exports.reduce((total, exp)=>total + exp.exports.length, 0);
372
- stats.sourceFilesWithExports = new Set(exports.map((exp)=>exp.source)).size;
373
- stats.sourceFilesScanned = (await (0, $cUHbR$fastglob)('**/*.{ts,tsx}', {
374
- cwd: sourcePath,
375
- ignore: [
376
- '**/node_modules/**',
377
- '**/dist/**',
378
- '**/build/**'
379
- ]
380
- })).length;
381
- const files = await $1d95f64f52ade133$var$findImports({
382
- packageName: packageInfo.name,
383
- monorepoRoot: targetPath
384
- });
385
- stats.totalFiles = files.length;
386
- stats.targetFilesFound = files;
387
- for (const file of files){
388
- const relativeFile = (0, $cUHbR$nodepath).relative(targetPath, file);
389
- if (ignoreTargetFiles.some((pattern)=>(0, $cUHbR$micromatch).isMatch(relativeFile, pattern))) {
390
- console.log(`Skipping ignored file: ${file} (matches pattern in ${ignoreTargetFiles.join(', ')})`);
391
- stats.filesSkipped++;
392
- continue;
393
- }
394
- try {
395
- const originalContent = (0, $cUHbR$readFileSync)(file, 'utf-8');
396
- await $1d95f64f52ade133$var$updateImports({
397
- filePath: file,
398
- packageName: packageInfo.name,
399
- exports: exports,
400
- includeExtension: options.includeExtension
401
- });
402
- const updatedContent = (0, $cUHbR$readFileSync)(file, 'utf-8');
403
- if (originalContent !== updatedContent) stats.importsUpdated++;
404
- else stats.filesWithNoUpdates++;
405
- stats.filesProcessed++;
406
- } catch (error) {
407
- stats.errors++;
408
- console.error(`Error processing ${file}:`, error);
409
- }
410
- }
411
- // Print migration summary
412
- console.log('\nMigration Summary');
413
- console.log(`Source files found: ${stats.sourceFilesScanned}`);
414
- console.log(`Source files with exports: ${stats.sourceFilesWithExports}`);
415
- console.log(`Source files skipped: ${stats.sourceFilesSkipped}`);
416
- console.log(`Exports found: ${stats.totalExports}`);
417
- console.log(`Target files found: ${stats.totalFiles}`);
418
- console.log(`Target files processed: ${stats.filesProcessed}`);
419
- console.log(`Target files with imports updated: ${stats.importsUpdated}`);
420
- console.log(`Target files with no changes needed: ${stats.filesWithNoUpdates}`);
421
- console.log(`Target files skipped: ${stats.filesSkipped}`);
422
- if (stats.errors > 0) console.log(`\nWarning: ${stats.errors} errors encountered during processing`);
423
- }
424
-
425
-
426
- /**
427
- * Configuration options for the migration process
428
- * @property {string} sourcePath - Path to the package being migrated
429
- * @property {string} targetPath - Path to the monorepo root to search for imports
430
- * @property {string[]} ignoreSourceFiles - Patterns to ignore when scanning source files
431
- * @property {string[]} ignoreTargetFiles - Patterns to ignore when scanning target files
432
- * @property {boolean} [includeExtension] - Whether to include file extensions in imports
433
- */ const $bf36973fbb2420ae$export$ba43bf67f3d48107 = {
434
- targetPath: '.',
435
- ignoreSourceFiles: [],
436
- ignoreTargetFiles: [],
437
- includeExtension: false
438
- };
439
-
440
-
441
- async function $f2a4372f35794f3d$export$f22da7240b7add18() {
442
- const program = new (0, $cUHbR$Command)();
443
- program.name('migrate-barrel-imports').description('CLI tool to migrate barrel files imports to direct imports').argument('<source-path>', 'Path to the package containing barrel files').argument('[target-path]', 'Path to the directory where imports should be migrated (default: current directory)').option('--ignore-source-files <patterns>', 'Comma-separated list of file patterns to ignore in source directory').option('--ignore-target-files <patterns>', 'Comma-separated list of file patterns to ignore in target directory').option('--no-extension', 'Exclude js|jsx|ts|tsx|mjs|cjs file extensions from import statements').allowUnknownOption(false).parse(process.argv);
444
- const args = program.args;
445
- if (!args[0]) {
446
- console.error('Error: source-path is required');
447
- process.exit(1);
448
- }
449
- const sourcePath = args[0];
450
- const targetPath = args[1] || (0, $bf36973fbb2420ae$export$ba43bf67f3d48107).targetPath;
451
- const options = program.opts();
452
- await (0, $1d95f64f52ade133$export$eb4d0c836e660010)({
453
- sourcePath: sourcePath,
454
- targetPath: targetPath,
455
- ignoreSourceFiles: options.ignoreSourceFiles ? options.ignoreSourceFiles.split(',') : (0, $bf36973fbb2420ae$export$ba43bf67f3d48107).ignoreSourceFiles,
456
- ignoreTargetFiles: options.ignoreTargetFiles ? options.ignoreTargetFiles.split(',') : (0, $bf36973fbb2420ae$export$ba43bf67f3d48107).ignoreTargetFiles,
457
- includeExtension: options.extension !== false ? true : (0, $bf36973fbb2420ae$export$ba43bf67f3d48107).includeExtension
458
- });
459
- }
460
-
461
-
462
- (async ()=>{
463
- await (0, $f2a4372f35794f3d$export$f22da7240b7add18)();
464
- })();
465
-
466
-
2
+ import{Command as e}from"commander";import{readFileSync as o,writeFileSync as t}from"node:fs";import r,{join as s}from"node:path";import i from"@babel/generator";import{parse as n}from"@babel/parser";import l from"@babel/traverse";import{isVariableDeclaration as a,isIdentifier as c,isExportSpecifier as p,isFunctionDeclaration as d,isImportSpecifier as u,importDeclaration as g,importSpecifier as f,stringLiteral as m}from"@babel/types";import h from"fast-glob";import x from"micromatch";let F=i.default||i,$=l.default||l;async function S(e){return JSON.parse(o(s(e,"package.json"),"utf-8"))}async function y({packagePath:e,ignoreSourceFiles:t=[],stats:r}){let i=[];console.log(`Scanning for TypeScript files in: ${e}`);let l=await h("**/*.{ts,tsx}",{cwd:e,ignore:["**/node_modules/**","**/dist/**","**/build/**"]});for(let u of(console.log(`Found ${l.length} TypeScript files`),l)){let l=t.some(e=>x.isMatch(u,e));l&&(console.log(`File matches ignore pattern but will be preserved: ${u}`),r&&r.sourceFilesSkipped++);let g=s(e,u);console.log(`
3
+ Processing file: ${u}`);let f=o(g,"utf-8");try{let e=n(f,{sourceType:"module",plugins:["typescript","jsx","decorators-legacy","classProperties","classPrivateProperties","classPrivateMethods","exportDefaultFrom","exportNamespaceFrom","functionBind","functionSent","dynamicImport","nullishCoalescingOperator","optionalChaining","objectRestSpread","asyncGenerators","doExpressions","importMeta","logicalAssignment","moduleBlocks","moduleStringNames","numericSeparator","partialApplication","privateIn","throwExpressions","topLevelAwait"]});$(e,{ExportNamedDeclaration(e){if(console.log(`Found named export in ${u}`),e.node.source){console.log(`Skipping re-export from ${e.node.source.value}`);return}if(e.node.declaration){if(a(e.node.declaration)){let o=e.node.declaration.declarations.map(e=>c(e.id)?e.id.name:null).filter(e=>null!==e);o.length>0&&(console.log(`Named exports found: ${o.join(", ")}`),i.push({source:u,exports:o,isIgnored:l}))}return}let o=e.node.specifiers.map(e=>{if(p(e)){let o=e.exported;return c(o)?o.name:o.value}return null}).filter(e=>null!==e);o.length>0&&(console.log(`Named exports found: ${o.join(", ")}`),i.push({source:u,exports:o,isIgnored:l}))},ExportDefaultDeclaration(e){console.log(`Found default export in ${u}`);let o=e.node.declaration;c(o)?(console.log(`Default export name: ${o.name}`),i.push({source:u,exports:[o.name],isIgnored:l})):d(o)&&o.id?(console.log(`Default export name: ${o.id.name}`),i.push({source:u,exports:[o.id.name],isIgnored:l})):console.log("Default export is not an identifier or named function")}})}catch(e){console.error(`Error parsing ${u}:`,e)}}return console.log(`
4
+ Total exports found: ${i.length}`),i}async function w({packageName:e,monorepoRoot:t}){try{let r=new Set,s=await h(["**/*.{ts,tsx}"],{cwd:t,absolute:!0,ignore:["**/node_modules/**","**/dist/**","**/build/**"],followSymbolicLinks:!1});for(let t of(console.log(`Found ${s.length} TypeScript files to scan`),s))try{let s=o(t,"utf-8"),i=n(s,{sourceType:"module",plugins:["typescript","jsx"]});$(i,{ImportDeclaration(o){let s=o.node.source.value;(s===e||s.startsWith(`${e}/`))&&r.add(t)}})}catch(e){console.error(`Error processing file ${t}:`,e)}let i=Array.from(r);if(i.length>0)for(let o of(console.log(`Found total of ${i.length} files with imports from ${e}`),console.log("Files found:"),i))console.log(` ${o}`);else console.log(`No files found importing from ${e}`);return i}catch(e){return console.error("Error finding imports:",e),[]}}async function E({filePath:e,packageName:r,exports:s,includeExtension:i=!0}){console.log(`
5
+ Processing file: ${e}`);let l=o(e,"utf-8");try{let o=n(l,{sourceType:"module",plugins:["typescript","jsx","decorators-legacy","classProperties","classPrivateProperties","classPrivateMethods","exportDefaultFrom","exportNamespaceFrom","functionBind","functionSent","dynamicImport","nullishCoalescingOperator","optionalChaining","objectRestSpread","asyncGenerators","doExpressions","importMeta","logicalAssignment","moduleBlocks","moduleStringNames","numericSeparator","partialApplication","privateIn","throwExpressions","topLevelAwait"]}),a=!1,p=0;if($(o,{ImportDeclaration(e){if(e.node.source.value===r){p++,console.log(`Found import from ${r}`);let o=e.node.specifiers,t=[];for(let e of o)if(u(e)){let o=e.imported,n=c(o)?o.name:o.value,l=s.find(e=>e.exports.includes(n));if(l){if(console.log(` Found export ${n} in ${l.source}`),l.isIgnored){console.log(` Keeping original import for ignored file: ${l.source}`);continue}let o=i?`${r}/${l.source}`:`${r}/${l.source.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,"")}`;t.push(g([f(e.local,e.imported)],m(o))),a=!0}else console.log(` Warning: Could not find export ${n}`)}if(t.length>0){let i=o.filter(e=>{if(!u(e))return!0;let o=c(e.imported)?e.imported.name:e.imported.value,t=s.find(e=>e.exports.includes(o));return!t||t.isIgnored});i.length>0&&t.unshift(g(i,m(r))),e.replaceWithMultiple(t),console.log(" Replaced import with direct imports from source files")}}}}),a){console.log(`Writing changes to ${e}`);let r=F(o,{retainLines:!1,retainFunctionParens:!0},l);t(e,r.code)}else p>0?console.log(`No changes needed for ${p} imports`):console.log("No imports found to update")}catch(o){console.error(`Error processing ${e}:`,o)}}async function P(e){let{sourcePath:t,targetPath:s,ignoreSourceFiles:i,ignoreTargetFiles:n}=e,l={totalFiles:0,filesProcessed:0,filesSkipped:0,importsUpdated:0,filesWithNoUpdates:0,errors:0,totalExports:0,sourceFilesScanned:0,sourceFilesWithExports:0,sourceFilesSkipped:0,targetFilesFound:[]},a=await S(t),c=await y({packagePath:t,ignoreSourceFiles:i,stats:l});l.totalExports=c.reduce((e,o)=>e+o.exports.length,0),l.sourceFilesWithExports=new Set(c.map(e=>e.source)).size,l.sourceFilesScanned=(await h("**/*.{ts,tsx}",{cwd:t,ignore:["**/node_modules/**","**/dist/**","**/build/**"]})).length;let p=await w({packageName:a.name,monorepoRoot:s});for(let t of(l.totalFiles=p.length,l.targetFilesFound=p,p)){let i=r.relative(s,t);if(n.some(e=>x.isMatch(i,e))){console.log(`Skipping ignored file: ${t} (matches pattern in ${n.join(", ")})`),l.filesSkipped++;continue}try{let r=o(t,"utf-8");await E({filePath:t,packageName:a.name,exports:c,includeExtension:e.includeExtension});let s=o(t,"utf-8");r!==s?l.importsUpdated++:l.filesWithNoUpdates++,l.filesProcessed++}catch(e){l.errors++,console.error(`Error processing ${t}:`,e)}}console.log("\nMigration Summary"),console.log(`Source files found: ${l.sourceFilesScanned}`),console.log(`Source files with exports: ${l.sourceFilesWithExports}`),console.log(`Source files skipped: ${l.sourceFilesSkipped}`),console.log(`Exports found: ${l.totalExports}`),console.log(`Target files found: ${l.totalFiles}`),console.log(`Target files processed: ${l.filesProcessed}`),console.log(`Target files with imports updated: ${l.importsUpdated}`),console.log(`Target files with no changes needed: ${l.filesWithNoUpdates}`),console.log(`Target files skipped: ${l.filesSkipped}`),l.errors>0&&console.log(`
6
+ Warning: ${l.errors} errors encountered during processing`)}let b={targetPath:".",ignoreSourceFiles:[],ignoreTargetFiles:[],includeExtension:!1};async function k(){let o=new e;o.name("migrate-barrel-imports").description("CLI tool to migrate barrel files imports to direct imports").argument("<source-path>","Path to the package containing barrel files").argument("[target-path]","Path to the directory where imports should be migrated (default: current directory)").option("--ignore-source-files <patterns>","Comma-separated list of file patterns to ignore in source directory").option("--ignore-target-files <patterns>","Comma-separated list of file patterns to ignore in target directory").option("--no-extension","Exclude js|jsx|ts|tsx|mjs|cjs file extensions from import statements").allowUnknownOption(!1).parse(process.argv);let t=o.args;t[0]||(console.error("Error: source-path is required"),process.exit(1));let r=t[0],s=t[1]||b.targetPath,i=o.opts();await P({sourcePath:r,targetPath:s,ignoreSourceFiles:i.ignoreSourceFiles?i.ignoreSourceFiles.split(","):b.ignoreSourceFiles,ignoreTargetFiles:i.ignoreTargetFiles?i.ignoreTargetFiles.split(","):b.ignoreTargetFiles,includeExtension:!1!==i.extension||b.includeExtension})}(async()=>{await k()})();
package/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "migrate-barrel-imports",
3
- "version": "0.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A CLI tool to migrate barrel imports in JavaScript/TypeScript monorepos",
5
- "files": ["dist/"],
5
+ "files": [
6
+ "dist/"
7
+ ],
6
8
  "main": "./dist/index.js",
9
+ "targets": {
10
+ "main": {
11
+ "optimize": true
12
+ }
13
+ },
7
14
  "keywords": [
8
15
  "typescript",
9
16
  "javascript",
@@ -52,7 +59,6 @@
52
59
  "@commitlint/cli": "19.8.0",
53
60
  "@commitlint/config-conventional": "19.8.0",
54
61
  "@semantic-release/changelog": "6.0.3",
55
- "@semantic-release/git": "10.0.1",
56
62
  "@types/babel__generator": "7.6.8",
57
63
  "@types/babel__traverse": "7.20.6",
58
64
  "@types/micromatch": "4.0.9",
@@ -69,8 +75,12 @@
69
75
  "author": "Martin Brandhaug",
70
76
  "license": "MIT",
71
77
  "lint-staged": {
72
- "*.{ts,json}": ["biome check --write"],
73
- "*.ts": ["tsc-files"]
78
+ "*.{ts,json}": [
79
+ "biome check --write"
80
+ ],
81
+ "*.ts": [
82
+ "tsc-files"
83
+ ]
74
84
  },
75
85
  "engines": {
76
86
  "node": ">=20"