Add explicit type annotations to AST traversal paths

Updated the performance monitor Vite plugin to add explicit type annotations to AST traversal callback parameters, improving type safety and clarity. Also removed a duplicate import in src/plugin/index.ts.
This commit is contained in:
手瓜一十雪 2025-08-15 19:02:53 +08:00
parent 1183fe2057
commit d069374a95
2 changed files with 11 additions and 319 deletions

View File

@ -1,6 +1,5 @@
import { NapCatOneBot11Adapter, OB11Message } from '@/onebot';
import { ChatType, NapCatCore } from '@/core';
import { ChatType, NapCatCore } from '@/core';
import { ActionMap } from '@/onebot/action';
import { OB11PluginAdapter } from '@/onebot/network/plugin';

View File

@ -56,16 +56,16 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
// 遍历AST
traverse(ast, {
// 检查是否已经导入了性能监控器
ImportDeclaration(path) {
ImportDeclaration(path: { node: { source: { value: string | string[]; }; }; }) {
if (path.node.source.value.includes('performance-monitor')) {
hasMonitorImport = true;
}
},
// 检查是否已经导出了性能监控器
ExportNamedDeclaration(path) {
ExportNamedDeclaration(path: { node: { declaration: t.Node | null | undefined; }; }) {
if (path.node.declaration && t.isVariableDeclaration(path.node.declaration)) {
path.node.declaration.declarations.forEach(declarator => {
path.node.declaration.declarations.forEach((declarator: { id: t.Node | null | undefined; }) => {
if (t.isIdentifier(declarator.id) && declarator.id.name === 'performanceMonitor') {
hasMonitorExport = true;
}
@ -74,8 +74,8 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 检查变量声明
VariableDeclaration(path) {
path.node.declarations.forEach(declarator => {
VariableDeclaration(path: { node: { declarations: any[]; }; }) {
path.node.declarations.forEach((declarator: { id: t.Node | null | undefined; }) => {
if (t.isIdentifier(declarator.id) && declarator.id.name === 'performanceMonitor') {
hasMonitorExport = true;
}
@ -83,7 +83,7 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 处理函数声明
FunctionDeclaration(path) {
FunctionDeclaration(path: { node: { id: { name: string; }; loc: { start: { line: number; }; }; }; }) {
const functionName = path.node.id?.name || 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
@ -92,7 +92,7 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 处理箭头函数
ArrowFunctionExpression(path) {
ArrowFunctionExpression(path: { parent: any; node: { loc: { start: { line: number; }; }; }; }) {
const parent = path.parent;
let functionName = 'anonymous';
@ -113,7 +113,7 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 处理函数表达式
FunctionExpression(path) {
FunctionExpression(path: { node: { id: { name: string; }; loc: { start: { line: number; }; }; }; }) {
const functionName = path.node.id?.name || 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
@ -122,7 +122,7 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 处理类方法
ClassMethod(path) {
ClassMethod(path: { node: { key: t.Node | null | undefined; loc: { start: { line: number; }; }; }; }) {
const methodName = t.isIdentifier(path.node.key) ? path.node.key.name : 'anonymous';
const className = getClassName(path);
const functionName = `${className}.${methodName}`;
@ -133,7 +133,7 @@ export function performanceMonitorPlugin(options: PerformancePluginOptions): Plu
},
// 处理对象方法
ObjectMethod(path) {
ObjectMethod(path: { node: { key: t.Node | null | undefined; loc: { start: { line: number; }; }; }; }) {
const methodName = t.isIdentifier(path.node.key) ? path.node.key.name : 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
@ -303,311 +303,4 @@ function getClassName(path: any): string {
return 'UnknownClass';
}
export default performanceMonitorPlugin;
import { Plugin } from 'vite';
import { parse } from '@babel/parser';
import traverseDefault from '@babel/traverse';
import generateDefault from '@babel/generator';
import * as t from '@babel/types';
import { resolve } from 'path';
// @ts-ignore
const traverse = traverseDefault.default || traverseDefault;
// @ts-ignore
const generate = generateDefault.default || generateDefault;
interface PerformancePluginOptions {
}
/**
* Vite插件
*/
export function performanceMonitorPlugin(options: PerformancePluginOptions): Plugin {
const exclude = [/node_modules/, /\.min\./, /performance-monitor\.ts$/, /packet/];
return {
name: 'performance-monitor',
transform(code: string, id: string) {
const fileName = id.replace(process.cwd(), '').replace(/\\/g, '/');
// 排除规则检查
if (exclude.some(pattern => pattern.test(id))) {
return null;
}
try {
// 解析AST
const ast = parse(code, {
sourceType: 'module',
plugins: [
'typescript',
'decorators-legacy',
'classProperties',
'asyncGenerators',
'bigInt',
'dynamicImport',
'exportDefaultFrom',
'exportNamespaceFrom',
'nullishCoalescingOperator',
'numericSeparator',
'optionalCatchBinding',
'optionalChaining',
'topLevelAwait'
]
});
let hasMonitorImport = false;
let hasMonitorExport = false;
let needsMonitor = false;
// 遍历AST
traverse(ast, {
// 检查是否已经导入了性能监控器
ImportDeclaration(path) {
if (path.node.source.value.includes('performance-monitor')) {
hasMonitorImport = true;
}
},
// 检查是否已经导出了性能监控器
ExportNamedDeclaration(path) {
if (path.node.declaration && t.isVariableDeclaration(path.node.declaration)) {
path.node.declaration.declarations.forEach(declarator => {
if (t.isIdentifier(declarator.id) && declarator.id.name === 'performanceMonitor') {
hasMonitorExport = true;
}
});
}
},
// 检查变量声明
VariableDeclaration(path) {
path.node.declarations.forEach(declarator => {
if (t.isIdentifier(declarator.id) && declarator.id.name === 'performanceMonitor') {
hasMonitorExport = true;
}
});
},
// 处理函数声明
FunctionDeclaration(path) {
const functionName = path.node.id?.name || 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
instrumentFunction(path, functionName, fileName, lineNumber);
needsMonitor = true;
},
// 处理箭头函数
ArrowFunctionExpression(path) {
const parent = path.parent;
let functionName = 'anonymous';
if (t.isVariableDeclarator(parent) && t.isIdentifier(parent.id)) {
functionName = parent.id.name;
} else if (t.isProperty(parent) && t.isIdentifier(parent.key)) {
functionName = parent.key.name;
} else if (t.isAssignmentExpression(parent) && t.isMemberExpression(parent.left)) {
const property = parent.left.property;
if (t.isIdentifier(property)) {
functionName = property.name;
}
}
const lineNumber = path.node.loc?.start.line || 0;
instrumentFunction(path, functionName, fileName, lineNumber);
needsMonitor = true;
},
// 处理函数表达式
FunctionExpression(path) {
const functionName = path.node.id?.name || 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
instrumentFunction(path, functionName, fileName, lineNumber);
needsMonitor = true;
},
// 处理类方法
ClassMethod(path) {
const methodName = t.isIdentifier(path.node.key) ? path.node.key.name : 'anonymous';
const className = getClassName(path);
const functionName = `${className}.${methodName}`;
const lineNumber = path.node.loc?.start.line || 0;
instrumentFunction(path, functionName, fileName, lineNumber);
needsMonitor = true;
},
// 处理对象方法
ObjectMethod(path) {
const methodName = t.isIdentifier(path.node.key) ? path.node.key.name : 'anonymous';
const lineNumber = path.node.loc?.start.line || 0;
instrumentFunction(path, methodName, fileName, lineNumber);
needsMonitor = true;
}
});
if (!needsMonitor) {
return null;
}
// 如果需要监控但还没有导入且没有导出,则添加导入语句
if (!hasMonitorImport && !hasMonitorExport) {
const importDeclaration = t.importDeclaration(
[t.importSpecifier(t.identifier('performanceMonitor'), t.identifier('performanceMonitor'))],
t.stringLiteral('@/common/performance-monitor')
);
ast.program.body.unshift(importDeclaration);
}
// 生成新代码
const result = generate(ast, {
retainLines: true,
compact: false
});
return {
code: result.code,
map: result.map
};
} catch (error) {
console.warn(`性能监控插件处理文件 ${id} 时出错:`, error);
return null;
}
}
};
}
/**
*
*/
function instrumentFunction(
path: any,
functionName: string,
fileName: string,
lineNumber: number
) {
// 跳过已经被监控的函数
if (functionName.includes('__perf_monitor__')) {
return;
}
const isAsync = path.node.async;
const body = path.node.body;
// 确保函数体是块语句
if (!t.isBlockStatement(body)) {
// 对于箭头函数的表达式体,转换为块语句
const returnStatement = t.returnStatement(body);
path.node.body = t.blockStatement([returnStatement]);
}
const blockBody = path.node.body as t.BlockStatement;
// 生成唯一的调用ID变量名
const callIdVar = `__perf_monitor_${functionName.replace(/[^a-zA-Z0-9]/g, '_')}_${lineNumber}__`;
// 创建开始监控的语句
const startMonitoring = t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier(callIdVar),
t.callExpression(
t.memberExpression(
t.identifier('performanceMonitor'),
t.identifier('startFunction')
),
[
t.stringLiteral(functionName),
t.stringLiteral(fileName),
t.numericLiteral(lineNumber)
]
)
)
]);
// 创建结束监控的语句
const endMonitoring = t.expressionStatement(
t.callExpression(
t.memberExpression(
t.identifier('performanceMonitor'),
t.identifier('endFunction')
),
[
t.identifier(callIdVar),
t.stringLiteral(functionName)
]
)
);
if (isAsync) {
// 对于异步函数,需要在所有可能的返回点添加监控结束
instrumentAsyncFunction(blockBody, startMonitoring, endMonitoring, callIdVar, functionName);
} else {
// 对于同步函数使用try-finally确保监控结束
instrumentSyncFunction(blockBody, startMonitoring, endMonitoring);
}
}
/**
*
*/
function instrumentSyncFunction(
blockBody: t.BlockStatement,
startMonitoring: t.VariableDeclaration,
endMonitoring: t.ExpressionStatement
) {
const originalStatements = [...blockBody.body];
const tryStatement = t.tryStatement(
t.blockStatement(originalStatements),
null,
t.blockStatement([endMonitoring])
);
blockBody.body = [startMonitoring, tryStatement];
}
/**
*
*/
function instrumentAsyncFunction(
blockBody: t.BlockStatement,
startMonitoring: t.VariableDeclaration,
endMonitoring: t.ExpressionStatement,
callIdVar: string,
functionName: string
) {
const originalStatements = [...blockBody.body];
// 创建包装的异步执行体
const asyncTryStatement = t.tryStatement(
t.blockStatement(originalStatements),
null,
t.blockStatement([endMonitoring])
);
blockBody.body = [startMonitoring, asyncTryStatement];
}
/**
*
*/
function getClassName(path: any): string {
let current = path;
while (current) {
if (current.isClassDeclaration && current.isClassDeclaration()) {
return current.node.id?.name || 'AnonymousClass';
} else if (current.isClassExpression && current.isClassExpression()) {
return current.node.id?.name || 'AnonymousClass';
} else if (current.node && (t.isClassDeclaration(current.node) || t.isClassExpression(current.node))) {
return current.node.id?.name || 'AnonymousClass';
}
current = current.parent;
}
return 'UnknownClass';
}
export default performanceMonitorPlugin;
export default performanceMonitorPlugin;