
* chore: update packageManager version to pnpm@10.9.0 for compatibility improvements * chore: Update dependent versions and configurations to improve compatibility and stability - Update Node version to 22.1.0 - Updated pnpm version to 10.10.0 - Fixed syntax error in prettier command in lintstagedrc - Update dependent versions in pnpm-lock.yaml to ensure consistency - Update format and content in README documents to improve readability * fix: lint error
196 lines
4.8 KiB
TypeScript
196 lines
4.8 KiB
TypeScript
import type { CAC } from 'cac';
|
|
|
|
import { getPackages } from '@vben/node-utils';
|
|
|
|
import depcheck from 'depcheck';
|
|
|
|
// 默认配置
|
|
const DEFAULT_CONFIG = {
|
|
// 需要忽略的依赖匹配
|
|
ignoreMatches: [
|
|
'vite',
|
|
'vitest',
|
|
'unbuild',
|
|
'@vben/tsconfig',
|
|
'@vben/vite-config',
|
|
'@vben/tailwind-config',
|
|
'@types/*',
|
|
'@vben-core/design',
|
|
],
|
|
// 需要忽略的包
|
|
ignorePackages: [
|
|
'@vben/backend-mock',
|
|
'@vben/commitlint-config',
|
|
'@vben/eslint-config',
|
|
'@vben/lint-staged-config',
|
|
'@vben/node-utils',
|
|
'@vben/prettier-config',
|
|
'@vben/stylelint-config',
|
|
'@vben/tailwind-config',
|
|
'@vben/tsconfig',
|
|
'@vben/vite-config',
|
|
'@vben/vsh',
|
|
],
|
|
// 需要忽略的文件模式
|
|
ignorePatterns: ['dist', 'node_modules', 'public'],
|
|
};
|
|
|
|
interface DepcheckResult {
|
|
dependencies: string[];
|
|
devDependencies: string[];
|
|
missing: Record<string, string[]>;
|
|
}
|
|
|
|
interface DepcheckConfig {
|
|
ignoreMatches?: string[];
|
|
ignorePackages?: string[];
|
|
ignorePatterns?: string[];
|
|
}
|
|
|
|
interface PackageInfo {
|
|
dir: string;
|
|
packageJson: {
|
|
name: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 清理依赖检查结果
|
|
* @param unused - 依赖检查结果
|
|
*/
|
|
function cleanDepcheckResult(unused: DepcheckResult): void {
|
|
// 删除file:前缀的依赖提示,该依赖是本地依赖
|
|
Reflect.deleteProperty(unused.missing, 'file:');
|
|
|
|
// 清理路径依赖
|
|
Object.keys(unused.missing).forEach((key) => {
|
|
unused.missing[key] = (unused.missing[key] || []).filter(
|
|
(item: string) => !item.startsWith('/'),
|
|
);
|
|
if (unused.missing[key].length === 0) {
|
|
Reflect.deleteProperty(unused.missing, key);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 格式化依赖检查结果
|
|
* @param pkgName - 包名
|
|
* @param unused - 依赖检查结果
|
|
*/
|
|
function formatDepcheckResult(pkgName: string, unused: DepcheckResult): void {
|
|
const hasIssues =
|
|
Object.keys(unused.missing).length > 0 ||
|
|
unused.dependencies.length > 0 ||
|
|
unused.devDependencies.length > 0;
|
|
|
|
if (!hasIssues) {
|
|
return;
|
|
}
|
|
|
|
console.log('\n📦 Package:', pkgName);
|
|
|
|
if (Object.keys(unused.missing).length > 0) {
|
|
console.log('❌ Missing dependencies:');
|
|
Object.entries(unused.missing).forEach(([dep, files]) => {
|
|
console.log(` - ${dep}:`);
|
|
files.forEach((file) => console.log(` → ${file}`));
|
|
});
|
|
}
|
|
|
|
if (unused.dependencies.length > 0) {
|
|
console.log('⚠️ Unused dependencies:');
|
|
unused.dependencies.forEach((dep) => console.log(` - ${dep}`));
|
|
}
|
|
|
|
if (unused.devDependencies.length > 0) {
|
|
console.log('⚠️ Unused devDependencies:');
|
|
unused.devDependencies.forEach((dep) => console.log(` - ${dep}`));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 运行依赖检查
|
|
* @param config - 配置选项
|
|
*/
|
|
async function runDepcheck(config: DepcheckConfig = {}): Promise<void> {
|
|
try {
|
|
const finalConfig = {
|
|
...DEFAULT_CONFIG,
|
|
...config,
|
|
};
|
|
|
|
const { packages } = await getPackages();
|
|
|
|
let hasIssues = false;
|
|
|
|
await Promise.all(
|
|
packages.map(async (pkg: PackageInfo) => {
|
|
// 跳过需要忽略的包
|
|
if (finalConfig.ignorePackages.includes(pkg.packageJson.name)) {
|
|
return;
|
|
}
|
|
|
|
const unused = await depcheck(pkg.dir, {
|
|
ignoreMatches: finalConfig.ignoreMatches,
|
|
ignorePatterns: finalConfig.ignorePatterns,
|
|
});
|
|
|
|
cleanDepcheckResult(unused);
|
|
|
|
const pkgHasIssues =
|
|
Object.keys(unused.missing).length > 0 ||
|
|
unused.dependencies.length > 0 ||
|
|
unused.devDependencies.length > 0;
|
|
|
|
if (pkgHasIssues) {
|
|
hasIssues = true;
|
|
formatDepcheckResult(pkg.packageJson.name, unused);
|
|
}
|
|
}),
|
|
);
|
|
|
|
if (!hasIssues) {
|
|
console.log('\n✅ Dependency check completed, no issues found');
|
|
}
|
|
} catch (error) {
|
|
console.error(
|
|
'❌ Dependency check failed:',
|
|
error instanceof Error ? error.message : error,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 定义依赖检查命令
|
|
* @param cac - CAC实例
|
|
*/
|
|
function defineDepcheckCommand(cac: CAC): void {
|
|
cac
|
|
.command('check-dep')
|
|
.option(
|
|
'--ignore-packages <packages>',
|
|
'Packages to ignore, comma separated',
|
|
)
|
|
.option(
|
|
'--ignore-matches <matches>',
|
|
'Dependency patterns to ignore, comma separated',
|
|
)
|
|
.option(
|
|
'--ignore-patterns <patterns>',
|
|
'File patterns to ignore, comma separated',
|
|
)
|
|
.usage('Analyze project dependencies')
|
|
.action(async ({ ignoreMatches, ignorePackages, ignorePatterns }) => {
|
|
const config: DepcheckConfig = {
|
|
...(ignorePackages && { ignorePackages: ignorePackages.split(',') }),
|
|
...(ignoreMatches && { ignoreMatches: ignoreMatches.split(',') }),
|
|
...(ignorePatterns && { ignorePatterns: ignorePatterns.split(',') }),
|
|
};
|
|
|
|
await runDepcheck(config);
|
|
});
|
|
}
|
|
|
|
export { defineDepcheckCommand, type DepcheckConfig };
|