Skip to content

默认值

OneBot Commander 支持为可选参数设置默认值,当参数未提供时使用预设的值。

基本概念

什么是默认值

默认值允许你为可选参数指定一个预设值,当用户没有提供该参数时自动使用:

typescript
const commander = new Commander('ping [count:number={value:1}]');
// 匹配: "ping " -> { count: { value: 1 } }
// 匹配: "ping 5" -> { count: 5 }

语法格式:[参数名:类型={字段:值}]

支持的数据类型

类型默认值示例说明
text[msg:text={text:hello}]字符串默认值
number[count:number={value:10}]数字默认值
boolean[flag:boolean={value:true}]布尔默认值
face[emoji:face={id:1}]对象默认值

基础用法

文本默认值

typescript
const commander = new Commander('echo [message:text={text:Hello World}]');

// 有参数
const segments1 = [
  { type: 'text', data: { text: 'echo Custom message' } }
];
const result1 = commander.match(segments1);
// result1[0] = { message: 'Custom message' }

// 无参数
const segments2 = [
  { type: 'text', data: { text: 'echo ' } }
];
const result2 = commander.match(segments2);
// result2[0] = { message: { text: 'Hello World' } }

数字默认值

typescript
const commander = new Commander('count [limit:number={value:100}]');

// 有参数
const segments1 = [
  { type: 'text', data: { text: 'count 50' } }
];
const result1 = commander.match(segments1);
// result1[0] = { limit: 50 }

// 无参数
const segments2 = [
  { type: 'text', data: { text: 'count ' } }
];
const result2 = commander.match(segments2);
// result2[0] = { limit: { value: 100 } }

布尔默认值

typescript
const commander = new Commander('toggle [state:boolean={value:true}]');

// 有参数
const segments1 = [
  { type: 'text', data: { text: 'toggle false' } }
];
const result1 = commander.match(segments1);
// result1[0] = { state: false }

// 无参数
const segments2 = [
  { type: 'text', data: { text: 'toggle ' } }
];
const result2 = commander.match(segments2);
// result2[0] = { state: { value: true } }

对象默认值

typescript
const commander = new Commander('react [emoji:face={id:1}]');

// 有参数
const segments1 = [
  { type: 'text', data: { text: 'react ' } },
  { type: 'face', data: { id: 2 } }
];
const result1 = commander.match(segments1);
// result1[0] = { emoji: 2 }

// 无参数
const segments2 = [
  { type: 'text', data: { text: 'react ' } }
];
const result2 = commander.match(segments2);
// result2[0] = { emoji: { id: 1 } }

高级用法

多个默认值参数

typescript
const commander = new Commander('config [theme:text={text:dark}] [size:number={value:12}] [debug:boolean={value:false}]');

// 部分参数
const segments1 = [
  { type: 'text', data: { text: 'config light' } }
];
const result1 = commander.match(segments1);
// result1[0] = { theme: 'light', size: 12, debug: false }

// 无参数
const segments2 = [
  { type: 'text', data: { text: 'config' } }
];
const result2 = commander.match(segments2);
// result2[0] = { theme: 'dark', size: 12, debug: false }

复杂对象默认值

typescript
const commander = new Commander('user [settings:json={theme:"dark",lang:"zh"}]');

// 有自定义设置
const segments1 = [
  { type: 'text', data: { text: 'user' } },
  { type: 'json', data: { data: '{"theme":"light","lang":"en"}' } }
];
const result1 = commander.match(segments1);
// result1[0] = { settings: { theme: 'light', lang: 'en' } }

// 使用默认设置
const segments2 = [
  { type: 'text', data: { text: 'user' } }
];
const result2 = commander.match(segments2);
// result2[0] = { settings: { theme: 'dark', lang: 'zh' } }

条件默认值

typescript
const commander = new Commander('search [query:text] [limit:number={value:10}]');

commander.action((params) => {
  const { query, limit } = params;
  
  // 根据查询类型设置不同的默认限制
  let actualLimit = limit;
  if (query && query.includes('*')) {
    actualLimit = Math.max(limit, 50); // 通配符查询使用更大的限制
  }
  
  return { query, limit: actualLimit };
});

实际应用示例

分页系统

typescript
const pageCommander = new Commander('list [page:number={value:1}] [size:number={value:20}] [sort:text={value:id}]');

pageCommander.action(async (params) => {
  const { page, size, sort } = params;
  
  // 验证参数
  const validPage = Math.max(1, page);
  const validSize = Math.min(100, Math.max(1, size));
  
  // 执行查询
  const results = await fetchData({
    page: validPage,
    size: validSize,
    sort: sort
  });
  
  return {
    page: validPage,
    size: validSize,
    sort,
    total: results.total,
    items: results.items
  };
});

配置系统

typescript
const configCommander = new Commander('config [key:text] [value:text] [type:text={value:string}]');

configCommander.action(async (params) => {
  const { key, value, type } = params;
  
  if (!key) {
    // 显示所有配置
    return await getAllConfig();
  }
  
  if (!value) {
    // 显示特定配置
    return await getConfig(key);
  }
  
  // 设置配置
  let parsedValue = value;
  switch (type) {
    case 'number':
      parsedValue = Number(value);
      break;
    case 'boolean':
      parsedValue = value.toLowerCase() === 'true';
      break;
    case 'json':
      parsedValue = JSON.parse(value);
      break;
  }
  
  await setConfig(key, parsedValue);
  return { key, value: parsedValue, type };
});

搜索系统

typescript
const searchCommander = new Commander('search [query:text] [fuzzy:boolean={value:true}] [limit:number={value:50}]');

searchCommander.action(async (params) => {
  const { query, fuzzy, limit } = params;
  
  if (!query) {
    return { error: '搜索查询不能为空' };
  }
  
  const results = await performSearch({
    query,
    fuzzy,
    limit,
    includeMetadata: true
  });
  
  return {
    query,
    fuzzy,
    limit,
    results: results.items,
    total: results.total,
    time: results.time
  };
});

默认值处理技巧

动态默认值

typescript
const commander = new Commander('time [format:text={value:local}]');

commander.action((params) => {
  const { format } = params;
  
  const now = new Date();
  let result;
  
  switch (format) {
    case 'utc':
      result = now.toUTCString();
      break;
    case 'iso':
      result = now.toISOString();
      break;
    case 'local':
    default:
      result = now.toLocaleString();
      break;
  }
  
  return { format, time: result };
});

环境相关默认值

typescript
const commander = new Commander('log [level:text={value:info}] [output:text={value:console}]');

commander.action((params) => {
  const { level, output } = params;
  
  // 根据环境调整默认值
  const isProduction = process.env.NODE_ENV === 'production';
  const actualLevel = isProduction && level === 'debug' ? 'info' : level;
  const actualOutput = isProduction && output === 'console' ? 'file' : output;
  
  return {
    level: actualLevel,
    output: actualOutput,
    environment: process.env.NODE_ENV || 'development'
  };
});

用户偏好默认值

typescript
class UserPreferences {
  constructor() {
    this.preferences = new Map();
  }
  
  setPreference(userId, key, value) {
    if (!this.preferences.has(userId)) {
      this.preferences.set(userId, {});
    }
    this.preferences.get(userId)[key] = value;
  }
  
  getPreference(userId, key, defaultValue) {
    const userPrefs = this.preferences.get(userId);
    return userPrefs ? userPrefs[key] : defaultValue;
  }
}

const userPrefs = new UserPreferences();

const commander = new Commander('theme [color:text={value:blue}] [size:text={value:medium}]');

commander.action((params, ...remaining) => {
  const { color, size } = params;
  const userId = extractUserId(remaining);
  
  // 获取用户偏好,如果没有则使用默认值
  const userColor = userPrefs.getPreference(userId, 'theme.color', color);
  const userSize = userPrefs.getPreference(userId, 'theme.size', size);
  
  // 保存用户偏好
  userPrefs.setPreference(userId, 'theme.color', userColor);
  userPrefs.setPreference(userId, 'theme.size', userSize);
  
  return { color: userColor, size: userSize, userId };
});

错误处理

默认值验证

typescript
const commander = new Commander('validate [value:number={value:0}] [min:number={value:0}] [max:number={value:100}]');

commander.action((params) => {
  const { value, min, max } = params;
  
  // 验证默认值是否合理
  if (min > max) {
    throw new Error('最小值不能大于最大值');
  }
  
  if (value < min || value > max) {
    throw new Error(`${value} 超出范围 [${min}, ${max}]`);
  }
  
  return {
    value,
    min,
    max,
    valid: true,
    message: '验证通过'
  };
});

类型转换错误

typescript
const commander = new Commander('convert [value:text={value:0}] [type:text={value:number}]');

commander.action((params) => {
  const { value, type } = params;
  
  try {
    let converted;
    switch (type) {
      case 'number':
        converted = Number(value);
        if (isNaN(converted)) {
          throw new Error('无法转换为数字');
        }
        break;
      case 'boolean':
        converted = value.toLowerCase() === 'true';
        break;
      case 'json':
        converted = JSON.parse(value);
        break;
      default:
        converted = value;
    }
    
    return {
      original: value,
      converted,
      type,
      success: true
    };
  } catch (error) {
    return {
      original: value,
      error: error.message,
      type,
      success: false
    };
  }
});

性能优化

默认值缓存

typescript
const defaultValueCache = new Map();

function getDefaultValue(type, value) {
  const key = `${type}:${value}`;
  
  if (!defaultValueCache.has(key)) {
    let parsed;
    switch (type) {
      case 'number':
        parsed = Number(value);
        break;
      case 'boolean':
        parsed = value.toLowerCase() === 'true';
        break;
      case 'json':
        parsed = JSON.parse(value);
        break;
      default:
        parsed = value;
    }
    defaultValueCache.set(key, parsed);
  }
  
  return defaultValueCache.get(key);
}

const commander = new Commander('cached [value:number={value:100}]');
commander.action((params) => {
  const defaultValue = getDefaultValue('number', '100');
  return { value: params.value || defaultValue };
});

延迟计算默认值

typescript
const commander = new Commander('lazy [timestamp:number]');

commander.action((params) => {
  const { timestamp } = params;
  
  // 只在需要时计算时间戳
  const actualTimestamp = timestamp || Date.now();
  
  return {
    timestamp: actualTimestamp,
    date: new Date(actualTimestamp).toISOString()
  };
});

调试技巧

默认值日志

typescript
const commander = new Commander('debug [level:text={value:info}] [verbose:boolean={value:false}]');

commander.action((params) => {
  const { level, verbose } = params;
  
  console.log('参数:', params);
  console.log('使用的默认值:');
  console.log(`  level: ${level} (默认: info)`);
  console.log(`  verbose: ${verbose} (默认: false)`);
  
  return {
    level,
    verbose,
    timestamp: Date.now(),
    message: '调试信息已记录'
  };
});

默认值验证工具

typescript
function validateDefaultValues(pattern) {
  const defaultValueRegex = /\[([^:]+):([^=]+)=([^\]]+)\]/g;
  const matches = pattern.match(defaultValueRegex);
  
  if (matches) {
    console.log('发现默认值:');
    matches.forEach(match => {
      const [, name, type, defaultValue] = match.match(/\[([^:]+):([^=]+)=([^\]]+)\]/);
      console.log(`  参数: ${name}, 类型: ${type}, 默认值: ${defaultValue}`);
      
      // 验证默认值类型
      try {
        switch (type) {
          case 'number':
            if (isNaN(Number(defaultValue))) {
              console.warn(`    警告: 默认值 "${defaultValue}" 无法转换为数字`);
            }
            break;
          case 'boolean':
            if (!['true', 'false'].includes(defaultValue.toLowerCase())) {
              console.warn(`    警告: 默认值 "${defaultValue}" 不是有效的布尔值`);
            }
            break;
          case 'json':
            JSON.parse(defaultValue);
            break;
        }
      } catch (error) {
        console.error(`    错误: 默认值 "${defaultValue}" 类型验证失败:`, error.message);
      }
    });
  }
  
  return matches;
}

// 使用示例
validateDefaultValues('command [count:number={value:10}] [flag:boolean={value:true}] [data:json={"key":"value"}]');

最佳实践

1. 合理的默认值

typescript
// ✅ 好的默认值
const good = new Commander('ping [count:number={value:1}]');
const good2 = new Commander('config [theme:text={text:dark}]');

// ❌ 避免不合理的默认值
const bad = new Commander('delete [confirm:boolean={value:true}]'); // 危险操作不应默认为 true
const bad2 = new Commander('limit [max:number={value:999999}]'); // 默认值过大

2. 类型一致性

typescript
// ✅ 类型一致的默认值
const good = new Commander('number [value:number={value:0}]');
const good2 = new Commander('text [message:text={text:hello}]');

// ❌ 类型不一致
const bad = new Commander('number [value:number={value:abc}]'); // 数字类型使用字符串默认值

3. 用户友好

typescript
// ✅ 用户友好的默认值
const good = new Commander('search [query:text] [limit:number={value:20}]');

// ❌ 不友好的默认值
const bad = new Commander('search [query:text] [limit:number={value:1}]'); // 限制过小

常见问题

1. 默认值中的特殊字符

typescript
// 问题:默认值包含特殊字符
const commander = new Commander('echo [msg:text={text:Hello, World!}]');
// 这会导致解析错误

// 解决方案:使用转义或 JSON 格式
const commander = new Commander('echo [msg:text={text:Hello\\, World!}]');
// 或者
const commander = new Commander('echo [msg:text={text:Hello World}]');

2. 复杂对象默认值

typescript
// 问题:复杂对象默认值
const commander = new Commander('config [settings:json={theme:"dark",size:12}]');
// 这可能导致解析问题

// 解决方案:使用简单的默认值
const commander = new Commander('config [theme:text={text:dark}] [size:number={value:12}]');

3. 动态默认值

typescript
// 注意:模式中的默认值是静态的,不能在运行时动态计算
const commander = new Commander('time [format:text={value:local}]');

// 如果需要动态默认值,在回调函数中处理
commander.action((params) => {
  const { format } = params;
  const actualFormat = format || getCurrentTimeFormat(); // 动态获取默认值
  return getTime(actualFormat);
});

下一步


💡 提示

默认值可以大大改善用户体验,减少用户输入,但要注意设置合理且安全的默认值。

Released under the MIT License.