migrate-barrel-imports 1.5.1 → 1.7.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/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -6
- package/dist/migrate-barrel-imports.d.ts +33 -0
- package/dist/migrate-barrel-imports.d.ts.map +1 -0
- package/dist/migrate-barrel-imports.js +681 -0
- package/dist/options.d.ts +17 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +6 -0
- package/package.json +88 -86
package/dist/cli.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAIA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmD1C"}
|
package/dist/cli.js
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
import { Command } from 'commander';
|
2
|
+
import { migrateBarrelImports } from './migrate-barrel-imports';
|
3
|
+
import { defaultOptions } from './options';
|
4
|
+
export async function main() {
|
5
|
+
const program = new Command();
|
6
|
+
program
|
7
|
+
.name('migrate-barrel-imports')
|
8
|
+
.description('CLI tool to migrate barrel files imports to direct imports')
|
9
|
+
.argument('<source-path>', 'Glob pattern for source packages containing barrel files (e.g. "libs/*")')
|
10
|
+
.argument('[target-path]', 'Path to the directory where imports should be migrated (default: current directory)')
|
11
|
+
.option('--ignore-source-files <patterns>', 'Comma-separated list of file patterns to ignore in source directory')
|
12
|
+
.option('--ignore-target-files <patterns>', 'Comma-separated list of file patterns to ignore in target directory')
|
13
|
+
.option('--no-extension', 'Exclude js|jsx|ts|tsx|mjs|cjs file extensions from import statements')
|
14
|
+
.allowUnknownOption(false)
|
15
|
+
.parse(process.argv);
|
16
|
+
const args = program.args;
|
17
|
+
if (!args[0]) {
|
18
|
+
console.error('Error: source-path is required');
|
19
|
+
process.exit(1);
|
20
|
+
}
|
21
|
+
const sourcePath = args[0];
|
22
|
+
const targetPath = args[1] || defaultOptions.targetPath;
|
23
|
+
const options = program.opts();
|
24
|
+
await migrateBarrelImports({
|
25
|
+
sourcePath,
|
26
|
+
targetPath,
|
27
|
+
ignoreSourceFiles: options.ignoreSourceFiles
|
28
|
+
? options.ignoreSourceFiles.split(',')
|
29
|
+
: defaultOptions.ignoreSourceFiles,
|
30
|
+
ignoreTargetFiles: options.ignoreTargetFiles
|
31
|
+
? options.ignoreTargetFiles.split(',')
|
32
|
+
: defaultOptions.ignoreTargetFiles,
|
33
|
+
includeExtension: options.extension !== false ? true : defaultOptions.includeExtension
|
34
|
+
});
|
35
|
+
}
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
import
|
3
|
-
|
4
|
-
|
5
|
-
|
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()})();
|
2
|
+
import { main } from './cli';
|
3
|
+
void (async () => {
|
4
|
+
await main();
|
5
|
+
})();
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Tool for migrating TypeScript projects from barrel file exports to direct file imports
|
3
|
+
*
|
4
|
+
* This tool helps migrate TypeScript projects that use barrel files (index.ts files that re-export)
|
5
|
+
* to use direct imports from source files instead. This improves:
|
6
|
+
* - Tree-shaking efficiency
|
7
|
+
* - Build performance
|
8
|
+
* - Code maintainability
|
9
|
+
* - TypeScript compilation speed
|
10
|
+
*
|
11
|
+
* The migration process:
|
12
|
+
* 1. Scans source package for all exports
|
13
|
+
* 2. Finds all files importing from the package
|
14
|
+
* 3. Updates imports to point directly to source files
|
15
|
+
* 4. Preserves original import names and types
|
16
|
+
*/
|
17
|
+
import type { Options as MigrationOptions } from './options';
|
18
|
+
/**
|
19
|
+
* Main migration function that orchestrates the barrel file migration process
|
20
|
+
*
|
21
|
+
* Process flow:
|
22
|
+
* 1. Finds all source packages matching the glob pattern
|
23
|
+
* 2. For each package:
|
24
|
+
* - Reads package.json to get package name and configuration
|
25
|
+
* - Scans source package for all exports (named and default)
|
26
|
+
* - Finds all files in the monorepo that import from the package
|
27
|
+
* - Updates each import to point directly to source files
|
28
|
+
*
|
29
|
+
* @param {Options} options - Migration configuration options
|
30
|
+
* @returns {Promise<void>}
|
31
|
+
*/
|
32
|
+
export declare function migrateBarrelImports(options: MigrationOptions): Promise<void>;
|
33
|
+
//# sourceMappingURL=migrate-barrel-imports.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"migrate-barrel-imports.d.ts","sourceRoot":"","sources":["../src/migrate-barrel-imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAkCH,OAAO,KAAK,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,WAAW,CAAA;AA2tB5D;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,gBAAgB,GACvB,OAAO,CAAC,IAAI,CAAC,CAoFf"}
|
@@ -0,0 +1,681 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Tool for migrating TypeScript projects from barrel file exports to direct file imports
|
3
|
+
*
|
4
|
+
* This tool helps migrate TypeScript projects that use barrel files (index.ts files that re-export)
|
5
|
+
* to use direct imports from source files instead. This improves:
|
6
|
+
* - Tree-shaking efficiency
|
7
|
+
* - Build performance
|
8
|
+
* - Code maintainability
|
9
|
+
* - TypeScript compilation speed
|
10
|
+
*
|
11
|
+
* The migration process:
|
12
|
+
* 1. Scans source package for all exports
|
13
|
+
* 2. Finds all files importing from the package
|
14
|
+
* 3. Updates imports to point directly to source files
|
15
|
+
* 4. Preserves original import names and types
|
16
|
+
*/
|
17
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
18
|
+
import path from 'node:path';
|
19
|
+
import _generate from '@babel/generator';
|
20
|
+
import { parse } from '@babel/parser';
|
21
|
+
import _traverse from '@babel/traverse';
|
22
|
+
import { importDeclaration, importSpecifier, isClassDeclaration, isExportSpecifier, isFunctionDeclaration, isIdentifier, isImportDefaultSpecifier, isImportNamespaceSpecifier, isImportSpecifier, isTSEnumDeclaration, isTSInterfaceDeclaration, isTSTypeAliasDeclaration, isVariableDeclaration, stringLiteral } from '@babel/types';
|
23
|
+
import fg from 'fast-glob';
|
24
|
+
import micromatch from 'micromatch';
|
25
|
+
// @ts-expect-error
|
26
|
+
const generate = _generate.default || _generate;
|
27
|
+
// @ts-expect-error
|
28
|
+
const traverse = _traverse.default || _traverse;
|
29
|
+
// Common Babel configuration for parsing TypeScript files
|
30
|
+
const BABEL_CONFIG = {
|
31
|
+
sourceType: 'module',
|
32
|
+
plugins: [
|
33
|
+
'typescript',
|
34
|
+
'jsx',
|
35
|
+
'decorators-legacy',
|
36
|
+
'classProperties',
|
37
|
+
'classPrivateProperties',
|
38
|
+
'classPrivateMethods',
|
39
|
+
'exportDefaultFrom',
|
40
|
+
'exportNamespaceFrom',
|
41
|
+
'functionBind',
|
42
|
+
'functionSent',
|
43
|
+
'dynamicImport',
|
44
|
+
'nullishCoalescingOperator',
|
45
|
+
'optionalChaining',
|
46
|
+
'objectRestSpread',
|
47
|
+
'asyncGenerators',
|
48
|
+
'doExpressions',
|
49
|
+
'importMeta',
|
50
|
+
'logicalAssignment',
|
51
|
+
'moduleBlocks',
|
52
|
+
'moduleStringNames',
|
53
|
+
'numericSeparator',
|
54
|
+
'partialApplication',
|
55
|
+
'privateIn',
|
56
|
+
'throwExpressions',
|
57
|
+
'topLevelAwait'
|
58
|
+
]
|
59
|
+
};
|
60
|
+
/**
|
61
|
+
* Reads and parses the package.json file for a given package path
|
62
|
+
*
|
63
|
+
* @param {string} packagePath - The path to the package directory
|
64
|
+
* @returns {Promise<PackageJson>} The parsed package.json contents
|
65
|
+
* @throws {Error} If package.json cannot be read or parsed
|
66
|
+
*/
|
67
|
+
async function _getPackageInfo(packagePath) {
|
68
|
+
const packageJsonPath = path.join(packagePath, 'package.json');
|
69
|
+
const content = readFileSync(packageJsonPath, 'utf-8');
|
70
|
+
return JSON.parse(content);
|
71
|
+
}
|
72
|
+
/**
|
73
|
+
* Extracts export names from a declaration node
|
74
|
+
*/
|
75
|
+
function getExportNames(declaration) {
|
76
|
+
if (!declaration)
|
77
|
+
return [];
|
78
|
+
if (isVariableDeclaration(declaration)) {
|
79
|
+
return declaration.declarations
|
80
|
+
.map((d) => (isIdentifier(d.id) ? d.id.name : null))
|
81
|
+
.filter((name) => name !== null);
|
82
|
+
}
|
83
|
+
if (isFunctionDeclaration(declaration) && declaration.id) {
|
84
|
+
return [declaration.id.name];
|
85
|
+
}
|
86
|
+
if (isTSEnumDeclaration(declaration)) {
|
87
|
+
return [declaration.id.name];
|
88
|
+
}
|
89
|
+
if (isTSInterfaceDeclaration(declaration)) {
|
90
|
+
return [declaration.id.name];
|
91
|
+
}
|
92
|
+
if (isTSTypeAliasDeclaration(declaration)) {
|
93
|
+
return [declaration.id.name];
|
94
|
+
}
|
95
|
+
if (isClassDeclaration(declaration) && declaration.id) {
|
96
|
+
return [declaration.id.name];
|
97
|
+
}
|
98
|
+
return [];
|
99
|
+
}
|
100
|
+
/**
|
101
|
+
* Checks if a file is a barrel file by analyzing its exports
|
102
|
+
*
|
103
|
+
* @param {string} filePath - Path to the file to check
|
104
|
+
* @returns {Promise<boolean>} Whether the file is a barrel file
|
105
|
+
*/
|
106
|
+
async function isBarrelFile(filePath) {
|
107
|
+
try {
|
108
|
+
const content = readFileSync(filePath, 'utf-8');
|
109
|
+
const ast = parse(content, BABEL_CONFIG);
|
110
|
+
let hasReExports = false;
|
111
|
+
let _hasDirectExports = false;
|
112
|
+
traverse(ast, {
|
113
|
+
ExportNamedDeclaration(path) {
|
114
|
+
if (path.node.source) {
|
115
|
+
hasReExports = true;
|
116
|
+
}
|
117
|
+
else {
|
118
|
+
_hasDirectExports = true;
|
119
|
+
}
|
120
|
+
},
|
121
|
+
ExportDefaultDeclaration() {
|
122
|
+
_hasDirectExports = true;
|
123
|
+
}
|
124
|
+
});
|
125
|
+
// A barrel file typically has re-exports and may or may not have direct exports
|
126
|
+
return hasReExports;
|
127
|
+
}
|
128
|
+
catch (error) {
|
129
|
+
console.error(`Error checking if ${filePath} is a barrel file:`, error);
|
130
|
+
return false;
|
131
|
+
}
|
132
|
+
}
|
133
|
+
/**
|
134
|
+
* Recursively finds all exports in a package by scanning all TypeScript files
|
135
|
+
*
|
136
|
+
* This function:
|
137
|
+
* 1. Scans all .ts and .tsx files in the package
|
138
|
+
* 2. Identifies both named exports and default exports
|
139
|
+
* 3. Skips re-exports to avoid circular dependencies
|
140
|
+
* 4. Filters out ignored files based on patterns
|
141
|
+
* 5. Handles barrel files by tracking their re-exports
|
142
|
+
*
|
143
|
+
* @param {FindExportsParams} params - Parameters for finding exports
|
144
|
+
* @returns {Promise<ExportInfo[]>} Array of export information, including source file and exported names
|
145
|
+
*/
|
146
|
+
async function findExports({ packagePath, ignoreSourceFiles = [], stats }) {
|
147
|
+
const exports = [];
|
148
|
+
const barrelFiles = new Set();
|
149
|
+
const _processedFiles = new Set();
|
150
|
+
const _exportSources = {};
|
151
|
+
const exportFiles = {};
|
152
|
+
console.log(`Scanning for TypeScript and JavaScript files in: ${packagePath}`);
|
153
|
+
const allFiles = await fg('**/*.{ts,tsx,js,jsx}', {
|
154
|
+
cwd: packagePath,
|
155
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**']
|
156
|
+
});
|
157
|
+
console.log(`Found ${allFiles.length} files`);
|
158
|
+
// First pass: identify barrel files
|
159
|
+
for (const file of allFiles) {
|
160
|
+
const fullPath = path.join(packagePath, file);
|
161
|
+
if (await isBarrelFile(fullPath)) {
|
162
|
+
barrelFiles.add(file);
|
163
|
+
console.log(`Identified barrel file: ${file}`);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
// Second pass: process all files
|
167
|
+
for (const file of allFiles) {
|
168
|
+
// Mark files that match ignore patterns but still process them
|
169
|
+
const isIgnored = ignoreSourceFiles.some((pattern) => micromatch.isMatch(file, pattern));
|
170
|
+
if (isIgnored) {
|
171
|
+
console.log(`File matches ignore pattern but will be preserved: ${file}`);
|
172
|
+
if (stats) {
|
173
|
+
stats.sourceFilesSkipped++;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
const fullPath = path.join(packagePath, file);
|
177
|
+
console.log(`\nProcessing file: ${file}`);
|
178
|
+
const content = readFileSync(fullPath, 'utf-8');
|
179
|
+
try {
|
180
|
+
const ast = parse(content, BABEL_CONFIG);
|
181
|
+
const fileExports = [];
|
182
|
+
const reExports = {};
|
183
|
+
const fileExportSources = {};
|
184
|
+
const defaultExportNames = [];
|
185
|
+
traverse(ast, {
|
186
|
+
ExportNamedDeclaration(nodePath) {
|
187
|
+
// Handle re-exports from external packages
|
188
|
+
if (nodePath.node.source) {
|
189
|
+
const sourceValue = nodePath.node.source.value;
|
190
|
+
if (sourceValue.includes('node_modules') ||
|
191
|
+
!sourceValue.startsWith('.')) {
|
192
|
+
// Extract export names and their original source
|
193
|
+
nodePath.node.specifiers.forEach((specifier) => {
|
194
|
+
if (isExportSpecifier(specifier)) {
|
195
|
+
const exported = specifier.exported;
|
196
|
+
const exportName = isIdentifier(exported)
|
197
|
+
? exported.name
|
198
|
+
: exported.value;
|
199
|
+
reExports[exportName] = sourceValue;
|
200
|
+
fileExports.push(exportName);
|
201
|
+
fileExportSources[exportName] = file;
|
202
|
+
// Track all files that export this symbol
|
203
|
+
if (!exportFiles[exportName]) {
|
204
|
+
exportFiles[exportName] = [];
|
205
|
+
}
|
206
|
+
exportFiles[exportName].push(file);
|
207
|
+
}
|
208
|
+
});
|
209
|
+
return;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
// Handle variable declarations with exports
|
213
|
+
if (nodePath.node.declaration) {
|
214
|
+
const exportNames = getExportNames(nodePath.node.declaration);
|
215
|
+
if (exportNames.length > 0) {
|
216
|
+
fileExports.push(...exportNames);
|
217
|
+
exportNames.forEach((name) => {
|
218
|
+
fileExportSources[name] = file;
|
219
|
+
// Track all files that export this symbol
|
220
|
+
if (!exportFiles[name]) {
|
221
|
+
exportFiles[name] = [];
|
222
|
+
}
|
223
|
+
exportFiles[name].push(file);
|
224
|
+
});
|
225
|
+
}
|
226
|
+
}
|
227
|
+
// Handle export specifiers
|
228
|
+
const exportNames = nodePath.node.specifiers
|
229
|
+
.map((s) => {
|
230
|
+
if (isExportSpecifier(s)) {
|
231
|
+
const exported = s.exported;
|
232
|
+
const exportName = isIdentifier(exported)
|
233
|
+
? exported.name
|
234
|
+
: exported.value;
|
235
|
+
if (nodePath.node.source) {
|
236
|
+
// If it's a re-export from another file, track the source
|
237
|
+
const sourceValue = nodePath.node.source.value;
|
238
|
+
if (sourceValue.startsWith('.')) {
|
239
|
+
const resolvedPath = path.join(path.dirname(file), sourceValue);
|
240
|
+
fileExportSources[exportName] = resolvedPath.replace(/\.[^/.]+$/, '');
|
241
|
+
// Track all files that export this symbol
|
242
|
+
if (!exportFiles[exportName]) {
|
243
|
+
exportFiles[exportName] = [];
|
244
|
+
}
|
245
|
+
exportFiles[exportName].push(file);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
return exportName;
|
249
|
+
}
|
250
|
+
return null;
|
251
|
+
})
|
252
|
+
.filter((name) => name !== null);
|
253
|
+
if (exportNames.length > 0) {
|
254
|
+
fileExports.push(...exportNames);
|
255
|
+
exportNames.forEach((name) => {
|
256
|
+
if (!fileExportSources[name]) {
|
257
|
+
fileExportSources[name] = file;
|
258
|
+
}
|
259
|
+
});
|
260
|
+
}
|
261
|
+
},
|
262
|
+
ExportDefaultDeclaration(path) {
|
263
|
+
const exported = path.node.declaration;
|
264
|
+
const exportName = isIdentifier(exported)
|
265
|
+
? exported.name
|
266
|
+
: isFunctionDeclaration(exported) && exported.id
|
267
|
+
? exported.id.name
|
268
|
+
: isClassDeclaration(exported) && exported.id
|
269
|
+
? exported.id.name
|
270
|
+
: 'default';
|
271
|
+
fileExports.push(exportName);
|
272
|
+
fileExportSources[exportName] = file;
|
273
|
+
// If this is a named entity (class, function) being exported as default, track its name
|
274
|
+
if (exportName !== 'default') {
|
275
|
+
defaultExportNames.push(exportName);
|
276
|
+
}
|
277
|
+
}
|
278
|
+
});
|
279
|
+
if (fileExports.length > 0 || Object.keys(reExports).length > 0) {
|
280
|
+
exports.push({
|
281
|
+
source: file,
|
282
|
+
exports: fileExports,
|
283
|
+
isIgnored,
|
284
|
+
...(Object.keys(reExports).length > 0 && { reExports }),
|
285
|
+
...(Object.keys(fileExportSources).length > 0 && {
|
286
|
+
exportSources: fileExportSources
|
287
|
+
}),
|
288
|
+
...(defaultExportNames.length > 0 && { defaultExportNames }),
|
289
|
+
...((await isBarrelFile(fullPath)) && { isBarrelFile: true }),
|
290
|
+
...(Object.keys(exportFiles).length > 0 && { exportFiles })
|
291
|
+
});
|
292
|
+
// Print exports in a single line
|
293
|
+
if (fileExports.length > 0) {
|
294
|
+
console.log(`Found exports ${fileExports.join(', ')} in ${file}`);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
}
|
298
|
+
catch (error) {
|
299
|
+
console.error(`Error parsing ${file}:`, error);
|
300
|
+
}
|
301
|
+
}
|
302
|
+
console.log(`\nTotal exports found: ${exports.length}`);
|
303
|
+
console.log(`Barrel files found: ${barrelFiles.size}`);
|
304
|
+
return exports;
|
305
|
+
}
|
306
|
+
/**
|
307
|
+
* Finds all files in the monorepo that import from a specific package
|
308
|
+
*
|
309
|
+
* This function:
|
310
|
+
* 1. Uses fast-glob to find all TypeScript files
|
311
|
+
* 2. Parses each file's AST to find imports
|
312
|
+
* 3. Handles both direct package imports and subpath imports
|
313
|
+
* 4. Excludes node_modules, dist, and build directories
|
314
|
+
*
|
315
|
+
* @param {FindImportsParams} params - Parameters for finding imports
|
316
|
+
* @returns {Promise<string[]>} Array of file paths that import from the package
|
317
|
+
*/
|
318
|
+
async function findImports({ packageName, targetPath, stats: _stats }) {
|
319
|
+
try {
|
320
|
+
const allFiles = new Set();
|
321
|
+
// Find all TypeScript and JavaScript files in the monorepo
|
322
|
+
const files = await fg(['**/*.{ts,tsx,js,jsx}'], {
|
323
|
+
cwd: targetPath,
|
324
|
+
absolute: true,
|
325
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'],
|
326
|
+
followSymbolicLinks: false
|
327
|
+
});
|
328
|
+
console.log(`Found ${files.length} files to scan`);
|
329
|
+
// Scan each file for imports
|
330
|
+
for (const file of files) {
|
331
|
+
try {
|
332
|
+
const content = readFileSync(file, 'utf-8');
|
333
|
+
const ast = parse(content, BABEL_CONFIG);
|
334
|
+
traverse(ast, {
|
335
|
+
ImportDeclaration(path) {
|
336
|
+
const source = path.node.source.value;
|
337
|
+
// Check for exact package import or subpath import
|
338
|
+
if (source === packageName ||
|
339
|
+
source.startsWith(`${packageName}/`)) {
|
340
|
+
allFiles.add(file);
|
341
|
+
}
|
342
|
+
}
|
343
|
+
});
|
344
|
+
}
|
345
|
+
catch (error) {
|
346
|
+
console.error(`Error processing file ${file}:`, error);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
const uniqueFiles = Array.from(allFiles);
|
350
|
+
if (uniqueFiles.length > 0) {
|
351
|
+
console.log(`Found total of ${uniqueFiles.length} files with imports from ${packageName}`);
|
352
|
+
console.log('Files found:');
|
353
|
+
for (const file of uniqueFiles) {
|
354
|
+
console.log(` ${file}`);
|
355
|
+
}
|
356
|
+
}
|
357
|
+
else {
|
358
|
+
console.log(`No files found importing from ${packageName}`);
|
359
|
+
}
|
360
|
+
return uniqueFiles;
|
361
|
+
}
|
362
|
+
catch (error) {
|
363
|
+
console.error('Error finding imports:', error);
|
364
|
+
return [];
|
365
|
+
}
|
366
|
+
}
|
367
|
+
/**
|
368
|
+
* Updates imports in a file to point directly to source files instead of using barrel files
|
369
|
+
*
|
370
|
+
* This function:
|
371
|
+
* 1. Parses the file's AST to find imports from the package
|
372
|
+
* 2. For each import, finds the source file containing the export
|
373
|
+
* 3. Updates the import to point directly to the source file
|
374
|
+
* 4. Preserves original import names and types
|
375
|
+
* 5. Only modifies the file if changes are needed
|
376
|
+
*
|
377
|
+
* @param {UpdateImportsParams} params - Parameters for updating imports
|
378
|
+
* @returns {Promise<void>}
|
379
|
+
*/
|
380
|
+
async function updateImports({ filePath, packageName, exports, includeExtension = true, warnings: _warnings, stats: _stats }) {
|
381
|
+
console.log(`\nProcessing file: ${filePath}`);
|
382
|
+
const content = readFileSync(filePath, 'utf-8');
|
383
|
+
let modified = false;
|
384
|
+
try {
|
385
|
+
const ast = parse(content, BABEL_CONFIG);
|
386
|
+
const importDeclarations = [];
|
387
|
+
// First pass: collect all import declarations
|
388
|
+
traverse(ast, {
|
389
|
+
ImportDeclaration(path) {
|
390
|
+
const importSource = path.node.source.value;
|
391
|
+
if (importSource.startsWith(packageName)) {
|
392
|
+
importDeclarations.push(path.node);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
});
|
396
|
+
const importsBySource = new Map();
|
397
|
+
const remainingSpecifiers = [];
|
398
|
+
for (const declaration of importDeclarations) {
|
399
|
+
const _importSource = declaration.source.value;
|
400
|
+
const specifiers = declaration.specifiers;
|
401
|
+
for (const specifier of specifiers) {
|
402
|
+
if (isImportSpecifier(specifier)) {
|
403
|
+
const imported = specifier.imported;
|
404
|
+
const importName = isIdentifier(imported)
|
405
|
+
? imported.name
|
406
|
+
: imported.value;
|
407
|
+
const exportInfo = exports.find((e) => e.exports.includes(importName));
|
408
|
+
if (exportInfo) {
|
409
|
+
if (exportInfo.isIgnored) {
|
410
|
+
remainingSpecifiers.push(specifier);
|
411
|
+
continue;
|
412
|
+
}
|
413
|
+
// Check if this is a re-export from an external package
|
414
|
+
if (exportInfo.reExports?.[importName]) {
|
415
|
+
const reExportSource = exportInfo.reExports[importName];
|
416
|
+
if (!reExportSource.startsWith('.')) {
|
417
|
+
// Keep the original import from the external package
|
418
|
+
const sourcePath = reExportSource;
|
419
|
+
if (!importsBySource.has(sourcePath)) {
|
420
|
+
importsBySource.set(sourcePath, []);
|
421
|
+
}
|
422
|
+
importsBySource.get(sourcePath)?.push({
|
423
|
+
local: specifier.local,
|
424
|
+
imported: specifier.imported
|
425
|
+
});
|
426
|
+
modified = true;
|
427
|
+
continue;
|
428
|
+
}
|
429
|
+
}
|
430
|
+
// Then check if it's a direct export from index.ts
|
431
|
+
if (exportInfo.source === 'src/index.ts' &&
|
432
|
+
exportInfo.exports.includes(importName) &&
|
433
|
+
!exportInfo.reExports?.[importName]) {
|
434
|
+
// Handle entities that are exported as default
|
435
|
+
const isDefaultExportedEntity = exportInfo.defaultExportNames?.includes(importName);
|
436
|
+
if (isDefaultExportedEntity) {
|
437
|
+
// For entities that are exported as default, import directly from the package
|
438
|
+
const sourcePath = packageName;
|
439
|
+
if (!importsBySource.has(sourcePath)) {
|
440
|
+
importsBySource.set(sourcePath, []);
|
441
|
+
}
|
442
|
+
importsBySource.get(sourcePath)?.push({
|
443
|
+
local: specifier.local,
|
444
|
+
imported: specifier.imported
|
445
|
+
});
|
446
|
+
modified = true;
|
447
|
+
continue;
|
448
|
+
}
|
449
|
+
// Check if this is a named export or default export
|
450
|
+
if (importName !== 'default') {
|
451
|
+
// For each named export from index.ts, create a separate import source path
|
452
|
+
const sourcePath = includeExtension
|
453
|
+
? `${packageName}/${exportInfo.source}`
|
454
|
+
: `${packageName}/${exportInfo.source.replace(/\.[^/.]+$/, '')}`;
|
455
|
+
if (!importsBySource.has(sourcePath)) {
|
456
|
+
importsBySource.set(sourcePath, []);
|
457
|
+
}
|
458
|
+
importsBySource.get(sourcePath)?.push({
|
459
|
+
local: specifier.local,
|
460
|
+
imported: specifier.imported
|
461
|
+
});
|
462
|
+
modified = true;
|
463
|
+
continue;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
// Find the best source file for this export
|
467
|
+
const exportFiles = exportInfo.exportFiles?.[importName] || [];
|
468
|
+
let bestSourceFile = exportFiles[0]; // Default to first file if no better option
|
469
|
+
// Prefer main source files over auxiliary files
|
470
|
+
if (exportFiles.length > 1) {
|
471
|
+
// Remove story files, test files, and other auxiliary files from consideration
|
472
|
+
const mainFiles = exportFiles.filter((file) => !file.includes('.stories.') &&
|
473
|
+
!file.includes('.test.') &&
|
474
|
+
!file.includes('.spec.') &&
|
475
|
+
!file.includes('.stories/') &&
|
476
|
+
!file.includes('.test/') &&
|
477
|
+
!file.includes('.spec/'));
|
478
|
+
if (mainFiles.length > 0) {
|
479
|
+
bestSourceFile = mainFiles[0];
|
480
|
+
}
|
481
|
+
}
|
482
|
+
if (bestSourceFile) {
|
483
|
+
const sourcePath = includeExtension
|
484
|
+
? `${packageName}/${bestSourceFile}`
|
485
|
+
: `${packageName}/${bestSourceFile.replace(/\.[^/.]+$/, '')}`;
|
486
|
+
// Check if this import is aliased and if we already have the original import
|
487
|
+
const isAliased = specifier.local.name !== importName;
|
488
|
+
const hasOriginalImport = Array.from(importsBySource.values()).some((specs) => specs.some((spec) => spec.imported &&
|
489
|
+
isIdentifier(spec.imported) &&
|
490
|
+
spec.imported.name === importName));
|
491
|
+
// Only add the import if it's not aliased or if we don't have the original import yet
|
492
|
+
if (!isAliased || !hasOriginalImport) {
|
493
|
+
if (!importsBySource.has(sourcePath)) {
|
494
|
+
importsBySource.set(sourcePath, []);
|
495
|
+
}
|
496
|
+
importsBySource.get(sourcePath)?.push({
|
497
|
+
local: specifier.local,
|
498
|
+
imported: specifier.imported
|
499
|
+
});
|
500
|
+
modified = true;
|
501
|
+
}
|
502
|
+
continue;
|
503
|
+
}
|
504
|
+
remainingSpecifiers.push(specifier);
|
505
|
+
}
|
506
|
+
else if (isImportDefaultSpecifier(specifier) ||
|
507
|
+
isImportNamespaceSpecifier(specifier)) {
|
508
|
+
remainingSpecifiers.push(specifier);
|
509
|
+
}
|
510
|
+
}
|
511
|
+
}
|
512
|
+
}
|
513
|
+
// Second pass: update the AST with new imports
|
514
|
+
traverse(ast, {
|
515
|
+
ImportDeclaration(path) {
|
516
|
+
const importSource = path.node.source.value;
|
517
|
+
if (importSource.startsWith(packageName)) {
|
518
|
+
// Remove the original import declaration
|
519
|
+
path.remove();
|
520
|
+
}
|
521
|
+
}
|
522
|
+
});
|
523
|
+
// Add new import declarations
|
524
|
+
const newImports = [];
|
525
|
+
for (const [source, specifiers] of importsBySource) {
|
526
|
+
if (specifiers.length > 0) {
|
527
|
+
newImports.push(importDeclaration(specifiers.map(({ local, imported }) => importSpecifier(local, imported)), stringLiteral(source)));
|
528
|
+
if (_stats) {
|
529
|
+
_stats.importsMigrated += specifiers.length;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
}
|
533
|
+
// Add remaining specifiers if any
|
534
|
+
if (remainingSpecifiers.length > 0) {
|
535
|
+
newImports.push(importDeclaration(remainingSpecifiers, stringLiteral(packageName)));
|
536
|
+
}
|
537
|
+
// Add all new imports at the top of the file
|
538
|
+
if (newImports.length > 0) {
|
539
|
+
ast.program.body.unshift(...newImports);
|
540
|
+
modified = true;
|
541
|
+
}
|
542
|
+
if (modified) {
|
543
|
+
// Write changes back to file
|
544
|
+
const output = generate(ast, {
|
545
|
+
// To avoid removing spaces in code
|
546
|
+
retainLines: true,
|
547
|
+
retainFunctionParens: true
|
548
|
+
}, content).code;
|
549
|
+
writeFileSync(filePath, output);
|
550
|
+
console.log(`Writing changes to ${filePath}`);
|
551
|
+
if (_stats) {
|
552
|
+
_stats.importsUpdated++;
|
553
|
+
}
|
554
|
+
}
|
555
|
+
else if (_stats) {
|
556
|
+
_stats.noChangesNeeded++;
|
557
|
+
}
|
558
|
+
}
|
559
|
+
catch (error) {
|
560
|
+
console.error(`Error updating imports in ${filePath}:`, error);
|
561
|
+
}
|
562
|
+
}
|
563
|
+
/**
|
564
|
+
* Main migration function that orchestrates the barrel file migration process
|
565
|
+
*
|
566
|
+
* Process flow:
|
567
|
+
* 1. Finds all source packages matching the glob pattern
|
568
|
+
* 2. For each package:
|
569
|
+
* - Reads package.json to get package name and configuration
|
570
|
+
* - Scans source package for all exports (named and default)
|
571
|
+
* - Finds all files in the monorepo that import from the package
|
572
|
+
* - Updates each import to point directly to source files
|
573
|
+
*
|
574
|
+
* @param {Options} options - Migration configuration options
|
575
|
+
* @returns {Promise<void>}
|
576
|
+
*/
|
577
|
+
export async function migrateBarrelImports(options) {
|
578
|
+
const { sourcePath, targetPath, includeExtension = true } = options;
|
579
|
+
// Track migration statistics
|
580
|
+
const stats = {
|
581
|
+
sourcePackagesFound: 0,
|
582
|
+
sourcePackagesProcessed: 0,
|
583
|
+
sourcePackagesSkipped: 0,
|
584
|
+
sourceFilesFound: 0,
|
585
|
+
sourceFilesWithExports: 0,
|
586
|
+
sourceFilesSkipped: 0,
|
587
|
+
exportsFound: 0,
|
588
|
+
targetFilesFound: 0,
|
589
|
+
targetFilesProcessed: 0,
|
590
|
+
importsUpdated: 0,
|
591
|
+
noChangesNeeded: 0,
|
592
|
+
targetFilesSkipped: 0,
|
593
|
+
importsMigrated: 0
|
594
|
+
};
|
595
|
+
// Track warnings
|
596
|
+
const warnings = [];
|
597
|
+
try {
|
598
|
+
// Find source packages
|
599
|
+
const sourcePackages = await findSourcePackages(sourcePath);
|
600
|
+
stats.sourcePackagesFound = sourcePackages.length;
|
601
|
+
for (const packagePath of sourcePackages) {
|
602
|
+
console.log(`\nProcessing package: ${packagePath}`);
|
603
|
+
// Find exports in source package
|
604
|
+
const exports = await findExports({ packagePath, stats });
|
605
|
+
stats.exportsFound = exports.reduce((total, info) => total + info.exports.length, 0);
|
606
|
+
stats.sourceFilesWithExports = exports.length;
|
607
|
+
// Find files that import from this package
|
608
|
+
const packageName = await getPackageName(packagePath);
|
609
|
+
const targetFiles = await findImports({ packageName, targetPath, stats });
|
610
|
+
stats.targetFilesFound = targetFiles.length;
|
611
|
+
// Update imports in target files
|
612
|
+
for (const filePath of targetFiles) {
|
613
|
+
stats.targetFilesProcessed++;
|
614
|
+
await updateImports({
|
615
|
+
filePath,
|
616
|
+
packageName,
|
617
|
+
exports,
|
618
|
+
includeExtension,
|
619
|
+
warnings,
|
620
|
+
stats
|
621
|
+
});
|
622
|
+
}
|
623
|
+
stats.sourcePackagesProcessed++;
|
624
|
+
}
|
625
|
+
// Print migration summary
|
626
|
+
console.log('\nMigration Summary');
|
627
|
+
console.log(`Source packages found: ${stats.sourcePackagesFound}`);
|
628
|
+
console.log(`Source packages processed: ${stats.sourcePackagesProcessed}`);
|
629
|
+
console.log(`Source packages skipped: ${stats.sourcePackagesSkipped}`);
|
630
|
+
console.log(`Source files found: ${stats.sourceFilesFound}`);
|
631
|
+
console.log(`Source files with exports: ${stats.sourceFilesWithExports}`);
|
632
|
+
console.log(`Source files skipped: ${stats.sourceFilesSkipped}`);
|
633
|
+
console.log(`Exports found: ${stats.exportsFound}`);
|
634
|
+
console.log(`Target files found: ${stats.targetFilesFound}`);
|
635
|
+
console.log(`Target files processed: ${stats.targetFilesProcessed}`);
|
636
|
+
console.log(`Target files with imports updated: ${stats.importsUpdated}`);
|
637
|
+
console.log(`Target files with no changes needed: ${stats.noChangesNeeded}`);
|
638
|
+
console.log(`Target files skipped: ${stats.targetFilesSkipped}`);
|
639
|
+
console.log(`Total imports migrated: ${stats.importsMigrated}`);
|
640
|
+
if (warnings.length > 0) {
|
641
|
+
console.log('\nWarnings:');
|
642
|
+
warnings.forEach((warning) => console.log(` - ${warning}`));
|
643
|
+
}
|
644
|
+
}
|
645
|
+
catch (error) {
|
646
|
+
console.error('Error during migration:', error);
|
647
|
+
throw error;
|
648
|
+
}
|
649
|
+
}
|
650
|
+
/**
|
651
|
+
* Gets the package name from package.json
|
652
|
+
*
|
653
|
+
* @param {string} packagePath - Path to the package directory
|
654
|
+
* @returns {Promise<string>} Package name
|
655
|
+
*/
|
656
|
+
async function getPackageName(packagePath) {
|
657
|
+
const packageJsonPath = path.join(packagePath, 'package.json');
|
658
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
659
|
+
return packageJson.name;
|
660
|
+
}
|
661
|
+
/**
|
662
|
+
* Finds all source packages in the given path
|
663
|
+
*
|
664
|
+
* @param {string} sourcePath - Path to search for source packages
|
665
|
+
* @returns {Promise<string[]>} Array of package paths
|
666
|
+
*/
|
667
|
+
async function findSourcePackages(sourcePath) {
|
668
|
+
// Use a local variable instead of reassigning the parameter
|
669
|
+
const resolvedPath = path.isAbsolute(sourcePath)
|
670
|
+
? path.resolve(sourcePath)
|
671
|
+
: path.join(process.cwd(), sourcePath);
|
672
|
+
console.log(`Looking for source packages in: ${resolvedPath}`);
|
673
|
+
const packageJsonFiles = await fg('{package.json,**/package.json}', {
|
674
|
+
cwd: resolvedPath,
|
675
|
+
ignore: ['**/node_modules/**', '**/dist/**', '**/build/**'],
|
676
|
+
absolute: true
|
677
|
+
});
|
678
|
+
console.log(`Found ${packageJsonFiles.length} package.json files:`);
|
679
|
+
packageJsonFiles.forEach((file) => console.log(` - ${file}`));
|
680
|
+
return packageJsonFiles.map(path.dirname);
|
681
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
/**
|
2
|
+
* Configuration options for the migration process
|
3
|
+
* @property {string} sourcePath - Glob pattern for source packages to migrate
|
4
|
+
* @property {string} targetPath - Path to the monorepo root to search for imports
|
5
|
+
* @property {string[]} ignoreSourceFiles - Patterns to ignore when scanning source files
|
6
|
+
* @property {string[]} ignoreTargetFiles - Patterns to ignore when scanning target files
|
7
|
+
* @property {boolean} [includeExtension] - Whether to include file extensions in imports
|
8
|
+
*/
|
9
|
+
export type Options = {
|
10
|
+
sourcePath: string;
|
11
|
+
targetPath: string;
|
12
|
+
ignoreSourceFiles: string[];
|
13
|
+
ignoreTargetFiles: string[];
|
14
|
+
includeExtension?: boolean;
|
15
|
+
};
|
16
|
+
export declare const defaultOptions: Omit<Options, 'sourcePath'>;
|
17
|
+
//# sourceMappingURL=options.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAKtD,CAAA"}
|
package/dist/options.js
ADDED
package/package.json
CHANGED
@@ -1,88 +1,90 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
2
|
+
"name": "migrate-barrel-imports",
|
3
|
+
"version": "1.7.0",
|
4
|
+
"description": "A CLI tool to migrate barrel imports in JavaScript/TypeScript monorepos",
|
5
|
+
"files": [
|
6
|
+
"dist/"
|
7
|
+
],
|
8
|
+
"main": "./dist/index.js",
|
9
|
+
"module": "./dist/index.js",
|
10
|
+
"types": "./dist/index.d.ts",
|
11
|
+
"exports": {
|
12
|
+
".": {
|
13
|
+
"types": "./dist/index.d.ts",
|
14
|
+
"import": "./dist/index.js"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"keywords": [
|
18
|
+
"typescript",
|
19
|
+
"javascript",
|
20
|
+
"monorepo",
|
21
|
+
"cli",
|
22
|
+
"tool",
|
23
|
+
"migrate",
|
24
|
+
"barrel",
|
25
|
+
"import",
|
26
|
+
"imports"
|
27
|
+
],
|
28
|
+
"repository": {
|
29
|
+
"type": "git",
|
30
|
+
"url": "git+https://github.com/brandhaug/migrate-barrel-imports.git"
|
31
|
+
},
|
32
|
+
"bugs": {
|
33
|
+
"url": "https://github.com/brandhaug/migrate-barrel-imports/issues"
|
34
|
+
},
|
35
|
+
"homepage": "https://github.com/brandhaug/migrate-barrel-imports#readme",
|
36
|
+
"type": "module",
|
37
|
+
"bin": {
|
38
|
+
"migrate-barrel-imports": "dist/index.js"
|
39
|
+
},
|
40
|
+
"scripts": {
|
41
|
+
"build": "tsc",
|
42
|
+
"start": "node dist/index.js",
|
43
|
+
"lint": "biome lint",
|
44
|
+
"check-write": "biome check --write",
|
45
|
+
"typecheck": "tsc",
|
46
|
+
"prepare": "husky",
|
47
|
+
"test": "vitest",
|
48
|
+
"validate": "npm run lint && npm run typecheck && npm run test"
|
49
|
+
},
|
50
|
+
"dependencies": {
|
51
|
+
"@babel/generator": "7.28.0",
|
52
|
+
"@babel/parser": "7.28.0",
|
53
|
+
"@babel/traverse": "7.28.0",
|
54
|
+
"@babel/types": "7.28.2",
|
55
|
+
"commander": "14.0.0",
|
56
|
+
"fast-glob": "3.3.3",
|
57
|
+
"micromatch": "4.0.8",
|
58
|
+
"ts-morph": "26.0.0"
|
59
|
+
},
|
60
|
+
"devDependencies": {
|
61
|
+
"@biomejs/biome": "2.1.4",
|
62
|
+
"@commitlint/cli": "19.8.1",
|
63
|
+
"@commitlint/config-conventional": "19.8.1",
|
64
|
+
"@semantic-release/changelog": "6.0.3",
|
65
|
+
"@types/babel__generator": "7.27.0",
|
66
|
+
"@types/babel__traverse": "7.28.0",
|
67
|
+
"@types/micromatch": "4.0.9",
|
68
|
+
"execa": "9.6.0",
|
69
|
+
"husky": "9.1.7",
|
70
|
+
"lint-staged": "16.1.5",
|
71
|
+
"semantic-release": "24.2.7",
|
72
|
+
"tsc-files": "1.1.4",
|
73
|
+
"tsx": "4.20.3",
|
74
|
+
"typescript": "5.9.2",
|
75
|
+
"vitest": "3.2.4"
|
76
|
+
},
|
77
|
+
"author": "Martin Brandhaug",
|
78
|
+
"license": "MIT",
|
79
|
+
"lint-staged": {
|
80
|
+
"*.{ts,json}": [
|
81
|
+
"biome check --write"
|
82
|
+
],
|
83
|
+
"*.ts": [
|
84
|
+
"tsc-files"
|
85
|
+
]
|
86
|
+
},
|
87
|
+
"engines": {
|
88
|
+
"node": ">=20"
|
89
|
+
}
|
88
90
|
}
|