mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-18 20:30:08 +08:00
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:
parent
1183fe2057
commit
d069374a95
@ -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';
|
||||
|
||||
|
||||
@ -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;
|
||||
Loading…
Reference in New Issue
Block a user