Forráskód Böngészése

refactor: 优化参数解析逻辑并统一元数据存储方式

重构了参数解析函数 `parseCommandParams`,使其能够根据命令的元数据动态解析参数,并增加了参数类型验证和错误提示。同时,将 `paramMetadata` 的存储方式从 `Function` 改为 `string`,以便更清晰地标识元数据所属的方法。此外,修复了部分代码中的拼写错误和注释不一致问题。
枫林 3 hónapja
szülő
commit
1e26434ba4
4 módosított fájl, 48 hozzáadás és 32 törlés
  1. 1 1
      src/interface/plugin.ts
  2. 38 22
      src/lib/Plugins.ts
  3. 6 6
      src/lib/decorators.ts
  4. 3 3
      src/plugins/test.ts

+ 1 - 1
src/interface/plugin.ts

@@ -39,7 +39,7 @@ export interface Command {
         sendText: boolean;  // 是否发送文本
         [key: string]: any; // 其他模板配置
     };
-    paramMetadata: ParamMetadata[]; // 参数元数据
+    paramdata?: ParamMetadata[]; // 参数元数据
 }
 // 参数元数据接口
 export interface ParamMetadata {

+ 38 - 22
src/lib/Plugins.ts

@@ -9,7 +9,7 @@ import type {
 } from 'node-napcat-ts/dist/Interfaces.js';
 import * as cron from 'node-cron';
 import 'reflect-metadata';
-import { Command, Plugin, } from '../interface/plugin.js';
+import { Command, ParamMetadata, Plugin, } from '../interface/plugin.js';
 import * as fs from 'fs'
 import * as path from 'path'
 // 获取指令前缀
@@ -19,11 +19,10 @@ import { fileURLToPath } from 'node:url';
 import { qqBot } from "../app.js";
 import { IsPermission } from "./Permission.js";
 import { download } from "./download.js";
-import { commandList } from "./decorators.js";
+import { commandList, paramMetadata } from "./decorators.js";
 
 //WSSendParam
 const CMD_PREFIX = config?.cmd?.prefix ?? '#';
-export const getCommands = () => commandList;
 // 导出装饰器
 // export { param, ParamType };
 // export const plugins = pluginsDecorator;
@@ -395,7 +394,7 @@ async function handleCommand(context: PrivateFriendMessage | PrivateGroupMessage
             throw new Error('消息内容为空');
         }
         const message = context.message[0].data.text || '';
-        const parsedArgs = await parseCommandParams(message, context);
+        const parsedArgs = await parseCommandParams(message, context, command);
 
         botlogger.info('命令参数解析完成:' + JSON.stringify({
             command: command.cmd,
@@ -604,7 +603,7 @@ export function runcod(cmd: string | string[], desc: string): MethodDecorator {
                 enabled: false,
                 sendText: true
             },
-            paramMetadata: []
+            paramdata: paramMetadata.get(target.constructor.prototype[propertyKey]) || []
         };
 
         plugin.commands.push(command);
@@ -616,7 +615,7 @@ export function runcod(cmd: string | string[], desc: string): MethodDecorator {
 
 
 // 修改参数解析函数
-async function parseCommandParams(message: string, context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage): Promise<any[]> {
+async function parseCommandParams(message: string, context: PrivateFriendMessage | PrivateGroupMessage | GroupMessage,command:Command): Promise<any[]> {
     const cmdArgs = message.split(/\s+/).filter(Boolean);
 
     // 移除命令前缀和命令名
@@ -624,25 +623,42 @@ async function parseCommandParams(message: string, context: PrivateFriendMessage
     const paramArgs = parts.slice(2); // 跳过 #test param 这两个部分
 
     // 调试日志
-    botlogger.info('DEBUG - 命令参数:' + JSON.stringify({
-        message,
-        cmdArgs,
-        paramArgs,
-        parts
-    }));
+    botlogger.info('DEBUG - 命令参数:' + JSON.stringify({paramArgs}));
 
     const params: any[] = [];
-
-    // 添加参数
-    if (paramArgs.length > 0) {
-        for (let i = 0; i < paramArgs.length; i++) {
-            //数字转化
-            const num = Number(paramArgs[i]);
-            if (!isNaN(num)) {
-                params.push(num);
+    const param = paramMetadata.get(command.pluginId+"."+command.cmd);
+    if (param) {
+        for (const paramData of param) {
+            const { name, type, index, optional } = paramData;
+            const msg= `正确格式为: ${CMD_PREFIX}${command.pluginId} ${command.cmd} ${param.map(p => p.optional ? `[${p.name}]` :`<${p.name}>`).join(' ')}`
+            if (paramArgs.length < param?.length) {
+                throw new Error(`参数不足,${msg}`);
+            }
+            if (!optional && !paramArgs[index]) {
+                throw new Error(`参数 <${name}> 是必需的,${msg}`);   
+            }
+            switch (type) {
+                case "string":
+                    params[index] = paramArgs[index] || '';
+                    break;
+                case "number":
+                    params[index] = Number(paramArgs[index]) || 0;
+                    if (isNaN(params[index])) {
+                        throw new Error(`参数 ${name} 必须是数字,${msg}`);
+                    }
+                    break;
+                case "boolean":
+                    params[index] = paramArgs[index] === 'true';
+                        if (optional && paramArgs[index] === undefined) {
+                            params[index] = false;
+                        }
+                    break;
+                case "rest":
+                    params[index] = paramArgs.slice(index);
+                    break;
+                default:
+                    throw new Error(`未知参数类型: ${type},${msg}`);
             }
-            params.push(paramArgs[i]);
-
         }
     }
     // 添加 context 参数

+ 6 - 6
src/lib/decorators.ts

@@ -11,7 +11,7 @@ import { Plugin } from '../interface/plugin.js';
 
 
 // 存储参数元数据
-export const paramMetadata = new Map<Function, ParamMetadata[]>();
+export const paramMetadata = new Map<string, ParamMetadata[]>();
 // 存储命令的数组
 export const commandList: Plugin[] = [];
 
@@ -20,12 +20,13 @@ export function param(name: string, type: ParamType = ParamType.String, optional
 
     return function (target: any, propertyKey: string | symbol | undefined, parameterIndex: number): void {
         const actualPropertyKey = propertyKey!;
-        const fn = target[actualPropertyKey];
-        let metadata = paramMetadata.get(fn);
+        //获得fn所在的类名和方法名
+        const fnName = `${target.constructor.name}.${actualPropertyKey.toString()}`;
+        let metadata = paramMetadata.get(fnName);
 
         if (!metadata) {
             metadata = [];
-            paramMetadata.set(fn, metadata);
+            paramMetadata.set(fnName, metadata);
         }
 
         const paramData: ParamMetadata = {
@@ -152,7 +153,6 @@ export function plugins(config: PluginConfig): ClassDecorator {
                         }
                     };
                 },
-                paramMetadata: []
             };
 
             plugin.commands.push(helpCommand);
@@ -226,7 +226,7 @@ export function runcod(cmd: string | string[], desc: string, config: CommandConf
                         sendText: IsTest, // 默认不发送文本,
                         ...(config.template || {})
                     },
-                    paramMetadata: []
+                    paramdata: paramMetadata.get(target.constructor.prototype[propertyKey]) || [],
                 };
 
                 plugin.commands.push(command);

+ 3 - 3
src/plugins/test.ts

@@ -9,7 +9,7 @@ import botlogger from '../lib/logger.js';
 import { ParamType } from '../interface/plugin.js';
 
 @plugins({
-    id: "test", //插件ID,必须唯一,不能重复
+    id: "test", //插件ID,需与类名一致,唯一
     name: "测试插件", //插件名称,用于显示在菜单中
     version: "1.0.0", //插件版本号,用于显示在菜单中
     describe: "测试功能", //插件描述,用于显示在菜单中
@@ -19,7 +19,7 @@ import { ParamType } from '../interface/plugin.js';
         description: "显示帮助信息" //帮助信息描述
     }
 })
-export class Test {
+export class test {
     @runcod(["param"], "参数实例")//命令装饰器,用于注册命令
     async param(
         @param("参数1", ParamType.String) param1: string,//参数装饰器,用于解析参数
@@ -54,7 +54,7 @@ export class Test {
 
     @schedule('* */30 * * * *') // 每30分钟执行一次
     async testschedule() {
-        botlogger.info("定时任务测试")
+        // botlogger.info("定时任务测试")
     }
 
 }