migrate-barrel-imports 1.3.0 → 1.5.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.
- package/README.md +10 -4
- package/dist/index.js +6 -5
- package/package.json +1 -1
package/README.md
CHANGED
@@ -30,7 +30,7 @@ npx migrate-barrel-imports <source-path> [target-path] [options]
|
|
30
30
|
|
31
31
|
### Arguments
|
32
32
|
|
33
|
-
- `source-path`:
|
33
|
+
- `source-path`: Directory pattern for source packages (e.g. "libs/*", "packages/{ui,core}") (required)
|
34
34
|
- `target-path`: Path to the directory where imports should be migrated (default: current directory)
|
35
35
|
|
36
36
|
### Options
|
@@ -44,11 +44,17 @@ Options can be specified either before or after the arguments:
|
|
44
44
|
## Example
|
45
45
|
|
46
46
|
```bash
|
47
|
-
#
|
47
|
+
# Migrate a single package
|
48
48
|
migrate-barrel-imports ./packages/my-lib --ignore-source-files "**/__tests__/**,**/__mocks__/**" --ignore-target-files "**/*.test.ts"
|
49
49
|
|
50
|
-
#
|
51
|
-
migrate-barrel-imports --no-extension
|
50
|
+
# Migrate multiple packages using glob pattern
|
51
|
+
migrate-barrel-imports "libs/*" --no-extension
|
52
|
+
|
53
|
+
# Migrate specific packages using glob pattern
|
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
|
52
58
|
|
53
59
|
# Mix of options before and after arguments
|
54
60
|
migrate-barrel-imports --no-extension ./packages/my-lib --ignore-target-files "**/*.test.ts"
|
package/dist/index.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
import{Command as e}from"commander";import{readFileSync as
|
3
|
-
Processing file: ${
|
4
|
-
Total exports found: ${
|
5
|
-
Processing file: ${e}`);let
|
6
|
-
|
2
|
+
import{Command as e}from"commander";import o,{readFileSync as s,writeFileSync as r}from"node:fs";import t from"node:path";import n from"@babel/generator";import{parse as i}from"@babel/parser";import l from"@babel/traverse";import{isVariableDeclaration as a,isIdentifier as c,isFunctionDeclaration as p,isTSEnumDeclaration as d,isTSInterfaceDeclaration as g,isTSTypeAliasDeclaration as u,isClassDeclaration as f,isExportSpecifier as m,isImportSpecifier as h,importDeclaration as x,stringLiteral as $,importSpecifier as S}from"@babel/types";import F from"fast-glob";import k from"micromatch";let w=n.default||n,y=l.default||l;async function b(e){return JSON.parse(s(t.join(e,"package.json"),"utf-8"))}async function E({packagePath:e,ignoreSourceFiles:o=[],stats:r}){let n=[];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 x=t.join(e,h);console.log(`
|
3
|
+
Processing file: ${h}`);let $=s(x,"utf-8");try{let e=i($,{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"]});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){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(", ")}`),n.push({source:h,exports:o,isIgnored:l}))}else if(p(e.node.declaration)){let o=e.node.declaration.id?.name;o&&(console.log(`Found function export: ${o}`),n.push({source:h,exports:[o],isIgnored:l}))}else if(d(e.node.declaration)){let o=e.node.declaration.id.name;console.log(`Found enum export: ${o}`),n.push({source:h,exports:[o],isIgnored:l})}else if(g(e.node.declaration)){let o=e.node.declaration.id.name;console.log(`Found interface export: ${o}`),n.push({source:h,exports:[o],isIgnored:l})}else if(u(e.node.declaration)){let o=e.node.declaration.id.name;console.log(`Found type alias export: ${o}`),n.push({source:h,exports:[o],isIgnored:l})}else if(f(e.node.declaration)&&e.node.declaration.id){let o=e.node.declaration.id.name;console.log(`Found class export: ${o}`),n.push({source:h,exports:[o],isIgnored:l})}return}let o=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);o.length>0&&(console.log(`Named exports found: ${o.join(", ")}`),n.push({source:h,exports:o,isIgnored:l}))},ExportDefaultDeclaration(e){console.log(`Found default export in ${h}`);let o=e.node.declaration;c(o)?(console.log(`Default export name: ${o.name}`),n.push({source:h,exports:[o.name],isIgnored:l})):p(o)&&o.id?(console.log(`Default export name: ${o.id.name}`),n.push({source:h,exports:[o.id.name],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: ${n.length}`),n}async function P({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"),n=i(t,{sourceType:"module",plugins:["typescript","jsx"]});y(n,{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 n=Array.from(r);if(n.length>0)for(let o of(console.log(`Found total of ${n.length} files with imports from ${e}`),console.log("Files found:"),n))console.log(` ${o}`);else console.log(`No files found importing from ${e}`);return n}catch(e){return console.error("Error finding imports:",e),[]}}async function j({filePath:e,packageName:o,exports:t,includeExtension:n=!0,warnings:l,stats:a}){console.log(`
|
5
|
+
Processing file: ${e}`);let p=s(e,"utf-8");try{let s=i(p,{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,d=0,g=new Set;if(y(s,{ImportDeclaration(s){let r=s.node.source.value;if(!g.has(r)&&r===o){d++,console.log(`Found import from ${o}`);let i=s.node.specifiers,p=new Map,u=[],f=!1;for(let s of i)if(h(s)){let r=s.imported,i=c(r)?r.name:r.value,d=t.find(e=>e.exports.includes(i));if(d){if(console.log(` Found export ${i} in ${d.source}`),d.isIgnored){console.log(` Keeping original import for ignored file: ${d.source}`),u.push(s);continue}let e=n?`${o}/${d.source}`:`${o}/${d.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: ${i} in "${e}"`;console.log(` ${o}`),l&&l.push(o),u.push(s);continue}let o=`Could not find export ${i} 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"),g.add(r);return}let m=[];for(let[e,s]of(u.length>0&&m.push(x(u,$(o))),p.entries()))m.push(x(s.map(e=>S(e.local,e.imported)),$(e)));s.replaceWithMultiple(m),console.log(" Replaced import with direct imports from source files"),g.add(r)}}}),a){console.log(`Writing changes to ${e}`);let o=w(s,{retainLines:!1,retainFunctionParens:!0},p);r(e,o.code)}else d>0?console.log(`No changes needed for ${d} imports`):console.log("No imports found to update")}catch(o){a&&a.errors++,console.error(`Error processing ${e}:`,o)}}async function I(e){let{sourcePath:r,targetPath:n,ignoreSourceFiles:i,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:n,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 b(r),p=await E({packagePath:r,ignoreSourceFiles:i,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 d=await P({packageName:c.name,monorepoRoot:n});for(let o of(a.totalFiles+=d.length,a.targetFilesFound.push(...d),d)){let r=t.relative(n,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 j({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 T={targetPath:".",ignoreSourceFiles:[],ignoreTargetFiles:[],includeExtension:!1};async function v(){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]||T.targetPath,n=o.opts();await I({sourcePath:r,targetPath:t,ignoreSourceFiles:n.ignoreSourceFiles?n.ignoreSourceFiles.split(","):T.ignoreSourceFiles,ignoreTargetFiles:n.ignoreTargetFiles?n.ignoreTargetFiles.split(","):T.ignoreTargetFiles,includeExtension:!1!==n.extension||T.includeExtension})}(async()=>{await v()})();
|