fix: 修复了在箭头函数下检查不生效的问题

This commit is contained in:
Pan Qiancheng 2026-01-04 15:27:22 +08:00
parent d71a223138
commit dc071a47fd
2 changed files with 123 additions and 20 deletions

View File

@ -6,6 +6,12 @@ const ts = tslib_1.__importStar(require("typescript"));
const path = tslib_1.__importStar(require("path"));
const fs = tslib_1.__importStar(require("fs"));
const process_1 = require("process");
const verboseLogging = false;
const log = (...args) => {
if (verboseLogging) {
console.log('[tscBuilder]', ...args);
}
};
exports.OAK_IGNORE_TAGS = [
'@oak-ignore',
'@oak-ignore-asynccontext',
@ -92,6 +98,10 @@ function performCustomChecks(program, typeChecker, customConfig) {
if (!ts.isPropertyAccessExpression(node.expression)) {
return;
}
// 如果上一层是return则先跳过让外层函数调用来处理
if (ts.isReturnStatement(node.parent)) {
return;
}
const propertyAccess = node.expression;
const objectExpression = propertyAccess.expression;
// 获取对象的类型
@ -315,17 +325,26 @@ function performCustomChecks(program, typeChecker, customConfig) {
if (!ts.isCallExpression(node)) {
return;
}
// 添加这里 - 打印所有函数调用
const sourceFile = node.getSourceFile();
const callText = node.expression.getText(sourceFile);
log(`[DEBUG] 检查函数调用: ${callText}`);
// 获取被调用函数的符号
const signature = typeChecker.getResolvedSignature(node);
if (!signature) {
log(`[DEBUG] ${callText} - 无法获取签名`);
return;
}
const declaration = signature.getDeclaration();
if (!declaration) {
log(`[DEBUG] ${callText} - 无法获取声明`);
return;
}
log(`[DEBUG] ${callText} - 声明类型: ${ts.SyntaxKind[declaration.kind]}`);
// 检查这个函数是否包含 context 调用
if (containsContextCall(declaration)) {
const hasContext = containsContextCall(declaration);
log(`[DEBUG] ${callText} - 包含context调用: ${hasContext}`);
if (hasContext) {
const returnType = typeChecker.getReturnTypeOfSignature(signature);
// 如果函数不返回 Promise说明内部已经正确处理了异步调用
// 此时调用该函数不需要 await
@ -336,14 +355,18 @@ function performCustomChecks(program, typeChecker, customConfig) {
const containingFunction = findContainingFunction(node);
if (containingFunction) {
const fname = getFunctionName(containingFunction);
if (!fname) {
return;
}
const symbol = typeChecker.getSymbolAtLocation(fname);
if (symbol) {
functionsWithContextCalls.add(symbol);
if (fname) { // 只有当有名称时才标记,但不影响后续检查
const symbol = typeChecker.getSymbolAtLocation(fname);
if (symbol) {
functionsWithContextCalls.add(symbol);
}
}
}
if (ts.isReturnStatement(node.parent)) {
// 如果在 return 语句中,不在这里报警告
// 警告会传播到调用当前函数的地方
return;
}
// 检查是否被 await
if (!isAwaited(node)) {
const sourceFile = node.getSourceFile();
@ -366,7 +389,9 @@ function performCustomChecks(program, typeChecker, customConfig) {
// 辅助函数:检查函数声明是否包含 context 调用
function containsContextCall(node) {
const symbol = getSymbolOfDeclaration(node);
log(`[DEBUG containsContextCall] 节点类型: ${ts.SyntaxKind[node.kind]}, 有符号: ${!!symbol}`);
if (symbol && checkedFunctions.has(symbol)) {
log(`[DEBUG containsContextCall] 使用缓存结果: ${checkedFunctions.get(symbol)}`);
return checkedFunctions.get(symbol);
}
let hasContextCall = false;
@ -380,6 +405,7 @@ function performCustomChecks(program, typeChecker, customConfig) {
const targetModules = customConfig.context?.targetModules ||
['@project/context/BackendRuntimeContext'];
if (isAsyncContextType(objectType, targetModules)) {
log(`[DEBUG containsContextCall] 找到context调用: ${n.expression.getText()}`);
hasContextCall = true;
return;
}
@ -392,16 +418,23 @@ function performCustomChecks(program, typeChecker, customConfig) {
if (declaration && !isSameOrDescendant(declaration, node)) {
// 避免无限递归
const symbol = getSymbolOfDeclaration(declaration);
// 先检查缓存
if (symbol && functionsWithContextCalls.has(symbol)) {
hasContextCall = true;
return;
}
// 如果缓存中没有,递归检查该函数
if (containsContextCall(declaration)) {
hasContextCall = true;
return;
}
}
}
}
ts.forEachChild(n, visit);
}
visit(node);
log(`[DEBUG containsContextCall] 最终结果: ${hasContextCall}`);
if (symbol) {
checkedFunctions.set(symbol, hasContextCall);
}
@ -451,9 +484,21 @@ function performCustomChecks(program, typeChecker, customConfig) {
}
// 辅助函数:获取声明的符号
function getSymbolOfDeclaration(declaration) {
// 处理有名称的声明(函数声明、方法声明等)
if ('name' in declaration && declaration.name) {
return typeChecker.getSymbolAtLocation(declaration.name);
}
// 处理箭头函数:尝试从父节点(变量声明)获取符号
if (ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration)) {
const parent = declaration.parent;
if (ts.isVariableDeclaration(parent) && parent.name) {
return typeChecker.getSymbolAtLocation(parent.name);
}
// 处理作为属性值的情况
if (ts.isPropertyAssignment(parent) && parent.name) {
return typeChecker.getSymbolAtLocation(parent.name);
}
}
return undefined;
}
return diagnostics;
@ -511,7 +556,7 @@ function compile(configPath) {
const allDiagnostics = [
...ts.getPreEmitDiagnostics(program),
...emitResult.diagnostics,
...customDiagnostics
...customDiagnostics || []
];
// 输出诊断信息
allDiagnostics.forEach((diagnostic) => {

View File

@ -3,6 +3,14 @@ import * as path from 'path';
import * as fs from 'fs';
import { cwd } from 'process';
const verboseLogging = false;
const log = (...args: any[]) => {
if (verboseLogging) {
console.log('[tscBuilder]', ...args);
}
};
export const OAK_IGNORE_TAGS = [
'@oak-ignore',
'@oak-ignore-asynccontext',
@ -145,6 +153,11 @@ function performCustomChecks(
return;
}
// 如果上一层是return则先跳过让外层函数调用来处理
if (ts.isReturnStatement(node.parent)) {
return;
}
const propertyAccess = node.expression;
const objectExpression = propertyAccess.expression;
@ -416,19 +429,31 @@ function performCustomChecks(
return;
}
// 添加这里 - 打印所有函数调用
const sourceFile = node.getSourceFile();
const callText = node.expression.getText(sourceFile);
log(`[DEBUG] 检查函数调用: ${callText}`);
// 获取被调用函数的符号
const signature = typeChecker.getResolvedSignature(node);
if (!signature) {
log(`[DEBUG] ${callText} - 无法获取签名`);
return;
}
const declaration = signature.getDeclaration();
if (!declaration) {
log(`[DEBUG] ${callText} - 无法获取声明`);
return;
}
log(`[DEBUG] ${callText} - 声明类型: ${ts.SyntaxKind[declaration.kind]}`);
// 检查这个函数是否包含 context 调用
if (containsContextCall(declaration)) {
const hasContext = containsContextCall(declaration);
log(`[DEBUG] ${callText} - 包含context调用: ${hasContext}`);
if (hasContext) {
const returnType = typeChecker.getReturnTypeOfSignature(signature);
// 如果函数不返回 Promise说明内部已经正确处理了异步调用
@ -436,22 +461,25 @@ function performCustomChecks(
if (!isPromiseType(returnType)) {
return;
}
// 标记当前所在的函数
const containingFunction = findContainingFunction(node);
if (containingFunction) {
const fname = getFunctionName(containingFunction)
if (!fname) {
return;
}
const symbol = typeChecker.getSymbolAtLocation(
fname
);
if (symbol) {
functionsWithContextCalls.add(symbol);
const fname = getFunctionName(containingFunction);
if (fname) { // 只有当有名称时才标记,但不影响后续检查
const symbol = typeChecker.getSymbolAtLocation(fname);
if (symbol) {
functionsWithContextCalls.add(symbol);
}
}
}
if (ts.isReturnStatement(node.parent)) {
// 如果在 return 语句中,不在这里报警告
// 警告会传播到调用当前函数的地方
return;
}
// 检查是否被 await
if (!isAwaited(node)) {
const sourceFile = node.getSourceFile();
@ -478,10 +506,15 @@ function performCustomChecks(
// 辅助函数:检查函数声明是否包含 context 调用
function containsContextCall(node: ts.Node): boolean {
const symbol = getSymbolOfDeclaration(node as ts.SignatureDeclaration);
log(`[DEBUG containsContextCall] 节点类型: ${ts.SyntaxKind[node.kind]}, 有符号: ${!!symbol}`);
if (symbol && checkedFunctions.has(symbol)) {
log(`[DEBUG containsContextCall] 使用缓存结果: ${checkedFunctions.get(symbol)}`);
return checkedFunctions.get(symbol)!;
}
let hasContextCall = false;
function visit(n: ts.Node): void {
@ -495,6 +528,7 @@ function performCustomChecks(
['@project/context/BackendRuntimeContext'];
if (isAsyncContextType(objectType, targetModules)) {
log(`[DEBUG containsContextCall] 找到context调用: ${n.expression.getText()}`);
hasContextCall = true;
return;
}
@ -508,10 +542,18 @@ function performCustomChecks(
if (declaration && !isSameOrDescendant(declaration, node)) {
// 避免无限递归
const symbol = getSymbolOfDeclaration(declaration);
// 先检查缓存
if (symbol && functionsWithContextCalls.has(symbol)) {
hasContextCall = true;
return;
}
// 如果缓存中没有,递归检查该函数
if (containsContextCall(declaration)) {
hasContextCall = true;
return;
}
}
}
}
@ -520,6 +562,8 @@ function performCustomChecks(
}
visit(node);
log(`[DEBUG containsContextCall] 最终结果: ${hasContextCall}`);
if (symbol) {
checkedFunctions.set(symbol, hasContextCall);
}
@ -573,9 +617,23 @@ function performCustomChecks(
// 辅助函数:获取声明的符号
function getSymbolOfDeclaration(declaration: ts.SignatureDeclaration): ts.Symbol | undefined {
// 处理有名称的声明(函数声明、方法声明等)
if ('name' in declaration && declaration.name) {
return typeChecker.getSymbolAtLocation(declaration.name);
}
// 处理箭头函数:尝试从父节点(变量声明)获取符号
if (ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration)) {
const parent = declaration.parent;
if (ts.isVariableDeclaration(parent) && parent.name) {
return typeChecker.getSymbolAtLocation(parent.name);
}
// 处理作为属性值的情况
if (ts.isPropertyAssignment(parent) && parent.name) {
return typeChecker.getSymbolAtLocation(parent.name);
}
}
return undefined;
}
@ -647,7 +705,7 @@ function compile(configPath: string): void {
const allDiagnostics: readonly (ts.Diagnostic | CustomDiagnostic)[] = [
...ts.getPreEmitDiagnostics(program),
...emitResult.diagnostics,
...customDiagnostics
...customDiagnostics || []
];
// 输出诊断信息