feat: build支持skipExtraCheck和skipEmitDiagnostics参数,用于项目中快速检查web

This commit is contained in:
Pan Qiancheng 2026-01-12 11:19:18 +08:00
parent 23abd05811
commit 81e000fa07
3 changed files with 122 additions and 32 deletions

View File

@ -34,6 +34,8 @@ interface CustomDiagnostic {
export type CompileOptions = {
project?: string;
noEmit?: boolean;
skipExtraCheck?: boolean;
skipEmitDiagnostics?: boolean;
};
/**
*

View File

@ -175,6 +175,14 @@ const isIdentifierWithSymbol = (node, symbol, typeChecker) => {
* @returns boolean
*/
const isFileInCheckScope = (pwd, fileName, customConfig) => {
const isUpperFile = path.relative(pwd, fileName).startsWith('..');
if (isUpperFile) {
return false;
}
const inNodeModules = fileName.includes('node_modules');
if (inNodeModules) {
return false;
}
const patterns = customConfig.context?.filePatterns || ['**/*.ts', '**/*.tsx'];
const normalizedFileName = path.normalize(path.relative(pwd, fileName)).replace(/\\/g, '/');
for (const pattern of patterns) {
@ -206,13 +214,14 @@ function parseArgs(pargs) {
const args = pargs.slice(2);
const options = {
project: 'tsconfig.json',
noEmit: false
noEmit: false,
skipExtraCheck: false
};
for (let i = 0; i < args.length; i++) {
if (args[i] === '-p' || args[i] === '--project') {
if (i + 1 < args.length) {
options.project = args[i + 1];
break;
i++;
}
else {
console.error('error: option \'-p, --project\' argument missing');
@ -222,6 +231,12 @@ function parseArgs(pargs) {
else if (args[i] === '--noEmit') {
options.noEmit = true;
}
else if (args[i] === '--skipExtraCheck') {
options.skipExtraCheck = true;
}
else if (args[i] === '--skipEmitDiagnostics') {
options.skipEmitDiagnostics = true;
}
}
return options;
}
@ -1017,9 +1032,6 @@ function performCustomChecks(pwd, program, typeChecker, customConfig) {
const checkIndirectCalls = () => {
// 使用之前收集的调用列表,避免重复遍历
for (const [sourceFile, callsToCheck] of callsToCheckByFile.entries()) {
if (sourceFile.isDeclarationFile || sourceFile.fileName.includes('node_modules')) {
continue;
}
for (const node of callsToCheck) {
if (!ts.isCallExpression(node))
continue;
@ -2532,7 +2544,7 @@ function performCustomChecks(pwd, program, typeChecker, customConfig) {
};
// 信息收集
for (const sourceFile of program.getSourceFiles()) {
if (sourceFile.isDeclarationFile || sourceFile.fileName.includes('node_modules')) {
if (sourceFile.isDeclarationFile) {
continue;
}
// 文件名是否符合检查范围
@ -2761,30 +2773,55 @@ const compile = (pwd, options) => {
// 执行编译
emitResult = program.emit();
}
else {
console.log(`${colors.yellow}Emit skipped as per configuration.${colors.reset}`);
}
// 获取诊断信息
const allDiagnostics = [
...ts.getPreEmitDiagnostics(program),
...emitResult.diagnostics,
];
// 输出诊断信息
allDiagnostics.forEach((diagnostic, index) => printDiagnostic(pwd, diagnostic, index));
let index = 0;
let errCount = 0;
let warnCount = 0;
if (!options.skipEmitDiagnostics) {
allDiagnostics.forEach((diagnostic) => {
if (options.skipExtraCheck) {
const fileName = diagnostic.file ? path.resolve(diagnostic.file.fileName) : null;
if (fileName && !isFileInCheckScope(pwd, fileName, customConfig)) {
return; // 跳过非工作目录下的文件诊断
}
}
const level = getDiagnosticLevel(diagnostic);
if (level === 'error') {
errCount++;
}
else if (level === 'warning') {
warnCount++;
}
printDiagnostic(pwd, diagnostic, index);
index++;
});
}
else {
console.log(`${colors.yellow}Emit diagnostics skipped as per configuration.${colors.reset}`);
}
// 输出编译统计
const errorCount = allDiagnostics.filter(d => d.category === ts.DiagnosticCategory.Error).length;
const warningCount = allDiagnostics.filter(d => d.category === ts.DiagnosticCategory.Warning).length;
if (errorCount > 0 || warningCount > 0) {
if (errCount > 0 || warnCount > 0) {
if (allDiagnostics.length > 0) {
console.log('');
}
const parts = [];
if (errorCount > 0) {
parts.push(`${errorCount} error${errorCount !== 1 ? 's' : ''}`);
if (errCount > 0) {
parts.push(`${errCount} error${errCount !== 1 ? 's' : ''}`);
}
if (warningCount > 0) {
parts.push(`${warningCount} warning${warningCount !== 1 ? 's' : ''}`);
if (warnCount > 0) {
parts.push(`${warnCount} warning${warnCount !== 1 ? 's' : ''}`);
}
console.log(`Found ${parts.join(' and ')}.`);
}
if (errorCount > 0) {
if (errCount > 0) {
console.log(`${colors.red}Compilation failed due to errors.${colors.reset}`);
process.exit(1);
}
@ -2821,3 +2858,11 @@ const build = (pwd, args) => {
compile(pwd, options);
};
exports.build = build;
function getDiagnosticLevel(diagnostic) {
if (diagnostic.category === ts.DiagnosticCategory.Error) {
return 'error';
}
else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
return 'warning';
}
}

View File

@ -191,6 +191,14 @@ const isIdentifierWithSymbol = (
* @returns boolean
*/
const isFileInCheckScope = (pwd: string, fileName: string, customConfig: OakBuildChecksConfig): boolean => {
const isUpperFile = path.relative(pwd, fileName).startsWith('..')
if (isUpperFile) {
return false;
}
const inNodeModules = fileName.includes('node_modules');
if (inNodeModules) {
return false;
}
const patterns = customConfig.context?.filePatterns || ['**/*.ts', '**/*.tsx'];
const normalizedFileName = path.normalize(path.relative(pwd, fileName)).replace(/\\/g, '/');
for (const pattern of patterns) {
@ -275,6 +283,10 @@ const colors = {
export type CompileOptions = {
project?: string;
noEmit?: boolean;
// 忽略非当前工作目录下的文件检查
skipExtraCheck?: boolean;
// 忽略EmitDiagnostics
skipEmitDiagnostics?: boolean;
}
// 解析命令行参数
@ -282,20 +294,25 @@ function parseArgs(pargs: string[]): CompileOptions {
const args: string[] = pargs.slice(2);
const options: CompileOptions = {
project: 'tsconfig.json',
noEmit: false
noEmit: false,
skipExtraCheck: false
};
for (let i = 0; i < args.length; i++) {
if (args[i] === '-p' || args[i] === '--project') {
if (i + 1 < args.length) {
options.project = args[i + 1];
break;
i++;
} else {
console.error('error: option \'-p, --project\' argument missing');
process.exit(1);
}
} else if (args[i] === '--noEmit') {
options.noEmit = true;
} else if (args[i] === '--skipExtraCheck') {
options.skipExtraCheck = true;
} else if (args[i] === '--skipEmitDiagnostics') {
options.skipEmitDiagnostics = true;
}
}
@ -1269,10 +1286,6 @@ export function performCustomChecks(
const checkIndirectCalls = (): void => {
// 使用之前收集的调用列表,避免重复遍历
for (const [sourceFile, callsToCheck] of callsToCheckByFile.entries()) {
if (sourceFile.isDeclarationFile || sourceFile.fileName.includes('node_modules')) {
continue;
}
for (const node of callsToCheck) {
if (!ts.isCallExpression(node)) continue;
if (shouldSkipCheck(node)) continue;
@ -3159,7 +3172,7 @@ export function performCustomChecks(
// 信息收集
for (const sourceFile of program.getSourceFiles()) {
if (sourceFile.isDeclarationFile || sourceFile.fileName.includes('node_modules')) {
if (sourceFile.isDeclarationFile) {
continue;
}
// 文件名是否符合检查范围
@ -3456,6 +3469,8 @@ const compile = (pwd: string, options: CompileOptions): void => {
if (!options.noEmit) {
// 执行编译
emitResult = program.emit();
} else {
console.log(`${colors.yellow}Emit skipped as per configuration.${colors.reset}`);
}
// 获取诊断信息
@ -3465,28 +3480,47 @@ const compile = (pwd: string, options: CompileOptions): void => {
];
// 输出诊断信息
allDiagnostics.forEach((diagnostic, index) => printDiagnostic(pwd, diagnostic, index));
let index = 0;
let errCount = 0;
let warnCount = 0;
if (!options.skipEmitDiagnostics) {
allDiagnostics.forEach((diagnostic) => {
if (options.skipExtraCheck) {
const fileName = diagnostic.file ? path.resolve(diagnostic.file.fileName) : null;
if (fileName && !isFileInCheckScope(pwd, fileName, customConfig)) {
return; // 跳过非工作目录下的文件诊断
}
}
const level = getDiagnosticLevel(diagnostic);
if (level === 'error') {
errCount++;
} else if (level === 'warning') {
warnCount++;
}
printDiagnostic(pwd, diagnostic, index)
index++;
});
} else {
console.log(`${colors.yellow}Emit diagnostics skipped as per configuration.${colors.reset}`);
}
// 输出编译统计
const errorCount = allDiagnostics.filter(d => d.category === ts.DiagnosticCategory.Error).length;
const warningCount = allDiagnostics.filter(d => d.category === ts.DiagnosticCategory.Warning).length;
if (errorCount > 0 || warningCount > 0) {
if (errCount > 0 || warnCount > 0) {
if (allDiagnostics.length > 0) {
console.log('');
}
const parts: string[] = [];
if (errorCount > 0) {
parts.push(`${errorCount} error${errorCount !== 1 ? 's' : ''}`);
if (errCount > 0) {
parts.push(`${errCount} error${errCount !== 1 ? 's' : ''}`);
}
if (warningCount > 0) {
parts.push(`${warningCount} warning${warningCount !== 1 ? 's' : ''}`);
if (warnCount > 0) {
parts.push(`${warnCount} warning${warnCount !== 1 ? 's' : ''}`);
}
console.log(`Found ${parts.join(' and ')}.`);
}
if (errorCount > 0) {
if (errCount > 0) {
console.log(`${colors.red}Compilation failed due to errors.${colors.reset}`);
process.exit(1);
}
@ -3526,3 +3560,12 @@ export const build = (pwd: string, args: any[]) => {
options.project = configPath;
compile(pwd, options);
}
function getDiagnosticLevel(diagnostic: ts.Diagnostic) {
if (diagnostic.category === ts.DiagnosticCategory.Error) {
return 'error';
} else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
return 'warning';
}
}