migrate-barrel-imports 1.4.0 → 1.5.1

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.
package/README.md CHANGED
@@ -52,12 +52,6 @@ migrate-barrel-imports "libs/*" --no-extension
52
52
 
53
53
  # Migrate specific packages using glob pattern
54
54
  migrate-barrel-imports "packages/{ui,core,utils}" --ignore-target-files "**/*.test.ts"
55
-
56
- # Migrate all packages in a monorepo
57
- migrate-barrel-imports "**/src" --no-extension
58
-
59
- # Mix of options before and after arguments
60
- migrate-barrel-imports --no-extension ./packages/my-lib --ignore-target-files "**/*.test.ts"
61
55
  ```
62
56
 
63
57
  ## Contributing
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{Command as e}from"commander";import o,{readFileSync as r,writeFileSync as t}from"node:fs";import 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 g,importDeclaration as u,importSpecifier as f,stringLiteral as m}from"@babel/types";import h from"fast-glob";import x from"micromatch";let $=i.default||i,S=l.default||l;async function F(e){return JSON.parse(r(s.join(e,"package.json"),"utf-8"))}async function k({packagePath:e,ignoreSourceFiles:o=[],stats:t}){let i=[];console.log(`Scanning for TypeScript and JavaScript files in: ${e}`);let l=await h("**/*.{ts,tsx,js,jsx}",{cwd:e,ignore:["**/node_modules/**","**/dist/**","**/build/**"]});for(let g of(console.log(`Found ${l.length} files`),l)){let l=o.some(e=>x.isMatch(g,e));l&&(console.log(`File matches ignore pattern but will be preserved: ${g}`),t&&t.sourceFilesSkipped++);let u=s.join(e,g);console.log(`
3
- Processing file: ${g}`);let f=r(u,"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"]});S(e,{ExportNamedDeclaration(e){if(console.log(`Found named export in ${g}`),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:g,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:g,exports:o,isIgnored:l}))},ExportDefaultDeclaration(e){console.log(`Found default export in ${g}`);let o=e.node.declaration;c(o)?(console.log(`Default export name: ${o.name}`),i.push({source:g,exports:[o.name],isIgnored:l})):d(o)&&o.id?(console.log(`Default export name: ${o.id.name}`),i.push({source:g,exports:[o.id.name],isIgnored:l})):console.log("Default export is not an identifier or named function")}})}catch(e){console.error(`Error parsing ${g}:`,e)}}return console.log(`
4
- Total exports found: ${i.length}`),i}async function y({packageName:e,monorepoRoot:o}){try{let t=new Set,s=await h(["**/*.{ts,tsx,js,jsx}"],{cwd:o,absolute:!0,ignore:["**/node_modules/**","**/dist/**","**/build/**"],followSymbolicLinks:!1});for(let o of(console.log(`Found ${s.length} files to scan`),s))try{let s=r(o,"utf-8"),i=n(s,{sourceType:"module",plugins:["typescript","jsx"]});S(i,{ImportDeclaration(r){let s=r.node.source.value;(s===e||s.startsWith(`${e}/`))&&t.add(o)}})}catch(e){console.error(`Error processing file ${o}:`,e)}let i=Array.from(t);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 w({filePath:e,packageName:o,exports:s,includeExtension:i=!0}){console.log(`
5
- Processing file: ${e}`);let l=r(e,"utf-8");try{let r=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(S(r,{ImportDeclaration(e){if(e.node.source.value===o){p++,console.log(`Found import from ${o}`);let r=e.node.specifiers,t=[];for(let e of r)if(g(e)){let r=e.imported,n=c(r)?r.name:r.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 r=i?`${o}/${l.source}`:`${o}/${l.source.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,"")}`;t.push(u([f(e.local,e.imported)],m(r))),a=!0}else console.log(` Warning: Could not find export ${n}`)}if(t.length>0){let i=r.filter(e=>{if(!g(e))return!0;let o=c(e.imported)?e.imported.name:e.imported.value,r=s.find(e=>e.exports.includes(o));return!r||r.isIgnored});i.length>0&&t.unshift(u(i,m(o))),e.replaceWithMultiple(t),console.log(" Replaced import with direct imports from source files")}}}}),a){console.log(`Writing changes to ${e}`);let o=$(r,{retainLines:!1,retainFunctionParens:!0},l);t(e,o.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 b(e){let{sourcePath:t,targetPath:i,ignoreSourceFiles:n,ignoreTargetFiles:l}=e,a={totalFiles:0,filesProcessed:0,filesSkipped:0,importsUpdated:0,filesWithNoUpdates:0,errors:0,totalExports:0,sourceFilesScanned:0,sourceFilesWithExports:0,sourceFilesSkipped:0,targetFilesFound:[],packagesProcessed:0,packagesSkipped:0},c=await h(t,{cwd:i,absolute:!0,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/target-app/**"],followSymbolicLinks:!1,onlyDirectories:!0}),p=[];for(let e of c){let r=s.join(e,"package.json");try{await o.promises.access(r),p.push(r)}catch{console.log(`No package.json found in ${e}, skipping`)}}for(let o of(console.log(`Found ${p.length} source packages to process`),p))try{let t=s.dirname(o);console.log(`
6
- Processing package: ${t}`);let c=await F(t),p=await k({packagePath:t,ignoreSourceFiles:n,stats:a});a.totalExports+=p.reduce((e,o)=>e+o.exports.length,0),a.sourceFilesWithExports+=new Set(p.map(e=>e.source)).size,a.sourceFilesScanned+=(await h("**/*.{ts,tsx}",{cwd:t,ignore:["**/node_modules/**","**/dist/**","**/build/**"]})).length;let d=await y({packageName:c.name,monorepoRoot:i});for(let o of(a.totalFiles+=d.length,a.targetFilesFound.push(...d),d)){let t=s.relative(i,o);if(l.some(e=>x.isMatch(t,e))){console.log(`Skipping ignored file: ${o} (matches pattern in ${l.join(", ")})`),a.filesSkipped++;continue}try{let t=r(o,"utf-8");await w({filePath:o,packageName:c.name,exports:p,includeExtension:e.includeExtension});let s=r(o,"utf-8");t!==s?a.importsUpdated++:a.filesWithNoUpdates++,a.filesProcessed++}catch(e){a.errors++,console.error(`Error processing ${o}:`,e)}}a.packagesProcessed++}catch(e){a.packagesSkipped++,console.error(`Error processing package ${o}:`,e)}console.log("\nMigration Summary"),console.log(`Source packages found: ${p.length}`),console.log(`Source packages processed: ${a.packagesProcessed}`),console.log(`Source packages skipped: ${a.packagesSkipped}`),console.log(`Source files found: ${a.sourceFilesScanned}`),console.log(`Source files with exports: ${a.sourceFilesWithExports}`),console.log(`Source files skipped: ${a.sourceFilesSkipped}`),console.log(`Exports found: ${a.totalExports}`),console.log(`Target files found: ${a.totalFiles}`),console.log(`Target files processed: ${a.filesProcessed}`),console.log(`Target files with imports updated: ${a.importsUpdated}`),console.log(`Target files with no changes needed: ${a.filesWithNoUpdates}`),console.log(`Target files skipped: ${a.filesSkipped}`),a.errors>0&&console.log(`
7
- Warning: ${a.errors} errors encountered during processing`)}let P={targetPath:".",ignoreSourceFiles:[],ignoreTargetFiles:[],includeExtension:!1};async function E(){let o=new e;o.name("migrate-barrel-imports").description("CLI tool to migrate barrel files imports to direct imports").argument("<source-path>",'Glob pattern for source packages containing barrel files (e.g. "libs/*")').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 r=o.args;r[0]||(console.error("Error: source-path is required"),process.exit(1));let t=r[0],s=r[1]||P.targetPath,i=o.opts();await b({sourcePath:t,targetPath:s,ignoreSourceFiles:i.ignoreSourceFiles?i.ignoreSourceFiles.split(","):P.ignoreSourceFiles,ignoreTargetFiles:i.ignoreTargetFiles?i.ignoreTargetFiles.split(","):P.ignoreTargetFiles,includeExtension:!1!==i.extension||P.includeExtension})}(async()=>{await E()})();
2
+ import{Command as e}from"commander";import o,{readFileSync as s,writeFileSync as r}from"node:fs";import t 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,isFunctionDeclaration as p,isTSEnumDeclaration as g,isTSInterfaceDeclaration as d,isTSTypeAliasDeclaration as u,isClassDeclaration as f,isExportSpecifier as m,isImportSpecifier as h,importDeclaration as $,stringLiteral as x,importSpecifier as S}from"@babel/types";import F from"fast-glob";import k from"micromatch";let w=i.default||i,y=l.default||l,b={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"]};async function E(e){return JSON.parse(s(t.join(e,"package.json"),"utf-8"))}async function P({packagePath:e,ignoreSourceFiles:o=[],stats:r}){let i=[];console.log(`Scanning for TypeScript and JavaScript files in: ${e}`);let l=await F("**/*.{ts,tsx,js,jsx}",{cwd:e,ignore:["**/node_modules/**","**/dist/**","**/build/**"]});for(let h of(console.log(`Found ${l.length} files`),l)){let l=o.some(e=>k.isMatch(h,e));l&&(console.log(`File matches ignore pattern but will be preserved: ${h}`),r&&r.sourceFilesSkipped++);let $=t.join(e,h);console.log(`
3
+ Processing file: ${h}`);let x=s($,"utf-8");try{let e=n(x,b);y(e,{ExportNamedDeclaration(e){if(console.log(`Found named export in ${h}`),e.node.source){let o=e.node.source.value;if(o.includes("node_modules")||!o.startsWith(".")){console.log(`Skipping re-export from external package: ${o}`);return}}if(e.node.declaration){var o;let s=(o=e.node.declaration)?a(o)?o.declarations.map(e=>c(e.id)?e.id.name:null).filter(e=>null!==e):p(o)&&o.id||g(o)||d(o)||u(o)||f(o)&&o.id?[o.id.name]:[]:[];s.length>0&&(console.log(`Named exports found: ${s.join(", ")}`),i.push({source:h,exports:s,isIgnored:l}))}let s=e.node.specifiers.map(e=>{if(m(e)){let o=e.exported;return c(o)?o.name:o.value}return null}).filter(e=>null!==e);s.length>0&&(console.log(`Named exports found: ${s.join(", ")}`),i.push({source:h,exports:s,isIgnored:l}))},ExportDefaultDeclaration(e){console.log(`Found default export in ${h}`);let o=e.node.declaration,s=c(o)?o.name:p(o)&&o.id?o.id.name:null;s?(console.log(`Default export name: ${s}`),i.push({source:h,exports:[s],isIgnored:l})):console.log("Default export is not an identifier or named function")}})}catch(e){console.error(`Error parsing ${h}:`,e)}}return console.log(`
4
+ Total exports found: ${i.length}`),i}async function j({packageName:e,monorepoRoot:o}){try{let r=new Set,t=await F(["**/*.{ts,tsx,js,jsx}"],{cwd:o,absolute:!0,ignore:["**/node_modules/**","**/dist/**","**/build/**"],followSymbolicLinks:!1});for(let o of(console.log(`Found ${t.length} files to scan`),t))try{let t=s(o,"utf-8"),i=n(t,b);y(i,{ImportDeclaration(s){let t=s.node.source.value;(t===e||t.startsWith(`${e}/`))&&r.add(o)}})}catch(e){console.error(`Error processing file ${o}:`,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 T({filePath:e,packageName:o,exports:t,includeExtension:i=!0,warnings:l,stats:a}){console.log(`
5
+ Processing file: ${e}`);let p=s(e,"utf-8");try{let s=n(p,b),a=!1,g=0,d=new Set;if(y(s,{ImportDeclaration(s){let r=s.node.source.value;if(!d.has(r)&&r===o){g++,console.log(`Found import from ${o}`);let n=s.node.specifiers,p=new Map,u=[],f=!1;for(let s of n)if(h(s)){let r=s.imported,n=c(r)?r.name:r.value,g=t.find(e=>e.exports.includes(n));if(g){if(console.log(` Found export ${n} in ${g.source}`),g.isIgnored){console.log(` Keeping original import for ignored file: ${g.source}`),u.push(s);continue}let e=i?`${o}/${g.source}`:`${o}/${g.source.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,"")}`;p.has(e)||p.set(e,[]),p.get(e)?.push({local:s.local,imported:s.imported}),a=!0,f=!0}else{if(t.some(e=>e.source.includes("node_modules")||!e.source.startsWith("."))){let o=`Skipping re-export from external package: ${n} in "${e}"`;console.log(` ${o}`),l&&l.push(o),u.push(s);continue}let o=`Could not find export ${n} in ${e}`;console.log(` Warning: ${o}`),l&&l.push(o),u.push(s)}}else u.push(s);if(!f){console.log(" Keeping original import due to no direct exports to migrate"),d.add(r);return}let m=[];for(let[e,s]of(u.length>0&&m.push($(u,x(o))),p.entries()))m.push($(s.map(e=>S(e.local,e.imported)),x(e)));s.replaceWithMultiple(m),console.log(" Replaced import with direct imports from source files"),d.add(r)}}}),a){console.log(`Writing changes to ${e}`);let o=w(s,{retainLines:!0,retainFunctionParens:!0},p);r(e,o.code)}else g>0?console.log(`No changes needed for ${g} imports`):console.log("No imports found to update")}catch(o){a&&a.errors++,console.error(`Error processing ${e}:`,o)}}async function N(e){let{sourcePath:r,targetPath:i,ignoreSourceFiles:n,ignoreTargetFiles:l}=e,a={totalFiles:0,filesProcessed:0,filesSkipped:0,importsUpdated:0,filesWithNoUpdates:0,errors:0,totalExports:0,sourceFilesScanned:0,sourceFilesWithExports:0,sourceFilesSkipped:0,targetFilesFound:[],packagesProcessed:0,packagesSkipped:0,warnings:[]},c=await F(r,{cwd:i,absolute:!0,ignore:["**/node_modules/**","**/dist/**","**/build/**","**/target-app/**"],followSymbolicLinks:!1,onlyDirectories:!0}),p=[];for(let e of c){let s=t.join(e,"package.json");try{await o.promises.access(s),p.push(s)}catch{console.log(`No package.json found in ${e}, skipping`)}}for(let o of(console.log(`Found ${p.length} source packages to process`),p))try{let r=t.dirname(o);console.log(`
6
+ Processing package: ${r}`);let c=await E(r),p=await P({packagePath:r,ignoreSourceFiles:n,stats:a});a.totalExports+=p.reduce((e,o)=>e+o.exports.length,0),a.sourceFilesWithExports+=new Set(p.map(e=>e.source)).size,a.sourceFilesScanned+=(await F("**/*.{ts,tsx}",{cwd:r,ignore:["**/node_modules/**","**/dist/**","**/build/**"]})).length;let g=await j({packageName:c.name,monorepoRoot:i});for(let o of(a.totalFiles+=g.length,a.targetFilesFound.push(...g),g)){let r=t.relative(i,o);if(l.some(e=>k.isMatch(r,e))){console.log(`Skipping ignored file: ${o} (matches pattern in ${l.join(", ")})`),a.filesSkipped++;continue}try{let r=s(o,"utf-8");await T({filePath:o,packageName:c.name,exports:p,includeExtension:e.includeExtension,warnings:a.warnings,stats:a});let t=s(o,"utf-8");r!==t?a.importsUpdated++:a.filesWithNoUpdates++,a.filesProcessed++}catch(e){a.errors++,console.error(`Error processing ${o}:`,e)}}a.packagesProcessed++}catch(e){a.packagesSkipped++,console.error(`Error processing package ${o}:`,e)}if(console.log("\nMigration Summary"),console.log(`Source packages found: ${p.length}`),console.log(`Source packages processed: ${a.packagesProcessed}`),console.log(`Source packages skipped: ${a.packagesSkipped}`),console.log(`Source files found: ${a.sourceFilesScanned}`),console.log(`Source files with exports: ${a.sourceFilesWithExports}`),console.log(`Source files skipped: ${a.sourceFilesSkipped}`),console.log(`Exports found: ${a.totalExports}`),console.log(`Target files found: ${a.totalFiles}`),console.log(`Target files processed: ${a.filesProcessed}`),console.log(`Target files with imports updated: ${a.importsUpdated}`),console.log(`Target files with no changes needed: ${a.filesWithNoUpdates}`),console.log(`Target files skipped: ${a.filesSkipped}`),a.warnings.length>0)for(let e of(console.log("\nWarnings:"),a.warnings))console.log(` - ${e}`);a.errors>0&&console.log(`
7
+ Warning: ${a.errors} errors encountered during processing`)}let v={targetPath:".",ignoreSourceFiles:[],ignoreTargetFiles:[],includeExtension:!1};async function D(){let o=new e;o.name("migrate-barrel-imports").description("CLI tool to migrate barrel files imports to direct imports").argument("<source-path>",'Glob pattern for source packages containing barrel files (e.g. "libs/*")').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 s=o.args;s[0]||(console.error("Error: source-path is required"),process.exit(1));let r=s[0],t=s[1]||v.targetPath,i=o.opts();await N({sourcePath:r,targetPath:t,ignoreSourceFiles:i.ignoreSourceFiles?i.ignoreSourceFiles.split(","):v.ignoreSourceFiles,ignoreTargetFiles:i.ignoreTargetFiles?i.ignoreTargetFiles.split(","):v.ignoreTargetFiles,includeExtension:!1!==i.extension||v.includeExtension})}(async()=>{await D()})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "migrate-barrel-imports",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "A CLI tool to migrate barrel imports in JavaScript/TypeScript monorepos",
5
5
  "files": [
6
6
  "dist/"