物业代码生成
This commit is contained in:
170
scripts/vsh/src/check-circular/index.ts
Normal file
170
scripts/vsh/src/check-circular/index.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import type { CAC } from 'cac';
|
||||
|
||||
import { extname } from 'node:path';
|
||||
|
||||
import { getStagedFiles } from '@vben/node-utils';
|
||||
|
||||
import { circularDepsDetect } from 'circular-dependency-scanner';
|
||||
|
||||
// 默认配置
|
||||
const DEFAULT_CONFIG = {
|
||||
allowedExtensions: ['.cjs', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.vue'],
|
||||
ignoreDirs: [
|
||||
'dist',
|
||||
'.turbo',
|
||||
'output',
|
||||
'.cache',
|
||||
'scripts',
|
||||
'internal',
|
||||
'packages/effects/request/src/',
|
||||
'packages/@core/ui-kit/menu-ui/src/',
|
||||
'packages/@core/ui-kit/popup-ui/src/',
|
||||
],
|
||||
threshold: 0, // 循环依赖的阈值
|
||||
} as const;
|
||||
|
||||
// 类型定义
|
||||
type CircularDependencyResult = string[];
|
||||
|
||||
interface CheckCircularConfig {
|
||||
allowedExtensions?: string[];
|
||||
ignoreDirs?: string[];
|
||||
threshold?: number;
|
||||
}
|
||||
|
||||
interface CommandOptions {
|
||||
config?: CheckCircularConfig;
|
||||
staged: boolean;
|
||||
verbose: boolean;
|
||||
}
|
||||
|
||||
// 缓存机制
|
||||
const cache = new Map<string, CircularDependencyResult[]>();
|
||||
|
||||
/**
|
||||
* 格式化循环依赖的输出
|
||||
* @param circles - 循环依赖结果
|
||||
*/
|
||||
function formatCircles(circles: CircularDependencyResult[]): void {
|
||||
if (circles.length === 0) {
|
||||
console.log('✅ No circular dependencies found');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('⚠️ Circular dependencies found:');
|
||||
circles.forEach((circle, index) => {
|
||||
console.log(`\nCircular dependency #${index + 1}:`);
|
||||
circle.forEach((file) => console.log(` → ${file}`));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查项目中的循环依赖
|
||||
* @param options - 检查选项
|
||||
* @param options.staged - 是否只检查暂存区文件
|
||||
* @param options.verbose - 是否显示详细信息
|
||||
* @param options.config - 自定义配置
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
async function checkCircular({
|
||||
config = {},
|
||||
staged,
|
||||
verbose,
|
||||
}: CommandOptions): Promise<void> {
|
||||
try {
|
||||
// 合并配置
|
||||
const finalConfig = {
|
||||
...DEFAULT_CONFIG,
|
||||
...config,
|
||||
};
|
||||
|
||||
// 生成忽略模式
|
||||
const ignorePattern = `**/{${finalConfig.ignoreDirs.join(',')}}/**`;
|
||||
|
||||
// 检查缓存
|
||||
const cacheKey = `${staged}-${process.cwd()}-${ignorePattern}`;
|
||||
if (cache.has(cacheKey)) {
|
||||
const cachedResults = cache.get(cacheKey);
|
||||
if (cachedResults) {
|
||||
verbose && formatCircles(cachedResults);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 检测循环依赖
|
||||
const results = await circularDepsDetect({
|
||||
absolute: staged,
|
||||
cwd: process.cwd(),
|
||||
ignore: [ignorePattern],
|
||||
});
|
||||
|
||||
if (staged) {
|
||||
let files = await getStagedFiles();
|
||||
const allowedExtensions = new Set(finalConfig.allowedExtensions);
|
||||
|
||||
// 过滤文件列表
|
||||
files = files.filter((file) => allowedExtensions.has(extname(file)));
|
||||
|
||||
const circularFiles: CircularDependencyResult[] = [];
|
||||
|
||||
for (const file of files) {
|
||||
for (const result of results) {
|
||||
const resultFiles = result.flat();
|
||||
if (resultFiles.includes(file)) {
|
||||
circularFiles.push(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
cache.set(cacheKey, circularFiles);
|
||||
verbose && formatCircles(circularFiles);
|
||||
} else {
|
||||
// 更新缓存
|
||||
cache.set(cacheKey, results);
|
||||
verbose && formatCircles(results);
|
||||
}
|
||||
|
||||
// 如果发现循环依赖,只输出警告信息
|
||||
if (results.length > 0) {
|
||||
console.log(
|
||||
'\n⚠️ Warning: Circular dependencies found, please check and fix',
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
'❌ Error checking circular dependencies:',
|
||||
error instanceof Error ? error.message : error,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义检查循环依赖的命令
|
||||
* @param cac - CAC实例
|
||||
*/
|
||||
function defineCheckCircularCommand(cac: CAC): void {
|
||||
cac
|
||||
.command('check-circular')
|
||||
.option('--staged', 'Only check staged files')
|
||||
.option('--verbose', 'Show detailed information')
|
||||
.option('--threshold <number>', 'Threshold for circular dependencies', {
|
||||
default: 0,
|
||||
})
|
||||
.option('--ignore-dirs <dirs>', 'Directories to ignore, comma separated')
|
||||
.usage('Analyze project circular dependencies')
|
||||
.action(async ({ ignoreDirs, staged, threshold, verbose }) => {
|
||||
const config: CheckCircularConfig = {
|
||||
threshold: Number(threshold),
|
||||
...(ignoreDirs && { ignoreDirs: ignoreDirs.split(',') }),
|
||||
};
|
||||
|
||||
await checkCircular({
|
||||
config,
|
||||
staged,
|
||||
verbose: verbose ?? true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { type CheckCircularConfig, defineCheckCircularCommand };
|
Reference in New Issue
Block a user