路由DSL
将复杂的配置转为链式,同时规范化指令风格和加强匹配速度
最小示例
import { Router } from 'alemonjs'
const router = Router.create({
events: ['message.create', 'private.message.create']
})
router.res({}, () => import('@src/response/resMaintenance'))
const app = router.group(
{
routeText: {
prefixes: ['/', '#', '#', '!', '!'],
stripPrefix: true,
allowBare: true
},
keyPolicy: {
maxWords: 2
}
},
() => import('@src/response/mw')
)
app.use(['帮助', 'help'], () => import('@src/response/help'))
export default router.define
一眼看懂
这套路由只用 4 个东西:
-
Router.create(...)建路由容器,给顶层res默认事件/平台。 -
router.res(...)注册顶层前置逻辑。 -
group(...)建一组共享中间件、共享输入规则的命令组。 -
use(...)注册具体命令。
什么时候用 router.res
router.res(...) 只放顶层前置逻辑。
适合放:
- 维护模式
- 新手引导
- select 转义
- 其他“消息一进来就要先检查”的逻辑
写法 懒加载
router.res({}, () => import('@src/response/resGuide'))
注意
顶层 res 往后放行要用:
next()
不要指望:
return true
什么时候用 group
group(...) 表示“这一组命令共享同一套规则”。
适合放:
- 共享中间件
- 输入前缀规则
- key 提取规则
- fallback 提示策略
- redispatch 深度
- duplicateKey 策略
基本写法
const app = router.group(
{
events: ['message.create', 'private.message.create']
},
() => import('@src/response/mwBan'),
() => import('@src/response/mw')
)
嵌套写法
const captcha = router.group(
{
fallback: {
suggest: false
}
},
() => import('@src/response/mwCaptcha')
)
什么时候用 use
use(...) 注册具体命令。
1. 单条命令
app.use('我', () => import('@src/response/message/me/res'))
2. 多个命令共用同一个实现
app.use(['帮助', '修仙帮助', 'help'], () => import('@src/response/help'))
3. 带参数规则
app.use(
{
path: '任务设置',
schema: {
usage: '/任务设置 <槽位> <步骤> <内容>',
args: [
{ name: 'slot', rules: [{ type: 'number', min: 1 }] },
{ name: 'step', rules: [{ type: 'number', min: 1 }] },
{ name: 'content', rules: [{ type: 'rest' }] }
]
}
},
() => import('@src/response/task/settings/res')
)
4. 多条配置化命令共用一个实现
app.use(
[
{ path: '学习功法', schema: skillSchema },
{ path: '隐藏功法', schema: hideSchema }
],
() => import('@src/response/skillBook/res')
)
key 怎么写
内部 key 一律不带前缀
正确:
app.use('签到', ...);
app.use('任务设置', ...);
不要写:
app.use('/签到', ...);
app.use('/任务设置', ...);
前缀由 routeText 处理,不属于 key。
routeText 怎么配
routeText 用来处理输入前缀,不改原始 MessageText,只影响路由命中。
常见写法
routeText: {
prefixes: ['/', '#', '#', '!', '!'],
stripPrefix: true,
allowBare: true
}
含义:
- 允许这些前缀
- 匹配时去掉前缀
- 不带前缀也能匹配
按平台单独配置
routeText: {
prefixes: ['/', '#'],
stripPrefix: true,
allowBare: true,
byPlatform: {
[discordPlatform]: {
prefixes: ['/'],
stripPrefix: true,
allowBare: false
}
}
}
这表示:
- 默认支持
/和# - Discord 只允许
/
keyPolicy 怎么配
控制命中时按几词取 key。
keyPolicy: {
maxWords: 2
}
支持:
1只按第一个词取 key2优先前两个词,再退回一个词
一般命令组保持 2 就行。
schema 怎么用
业务通过 useEvent() 读取时,应使用 event.current.__route 访问这段上下文。
命中后,路由层会自动把参数挂到:
e.__route.rawArgse.__route.parsedArgse.__route.params
推荐业务代码直接读:
e.__route.params
不要再自己拆:
e.MessageText
示例
const { slot, step, content } = e.__route.params
fallback 怎么配
当用户输入没命中时,是否提示“更接近哪个指令”。
fallback: {
suggest: true,
maxDistance: 2,
minInputLength: 2,
allowPrefixMatch: true
}
常见用法:
- 想完全关闭提示:
fallback: {
suggest: false
}
duplicateKey 怎么配
同一事件下,重复注册同一个 key 时怎么处理。
duplicateKey: 'warn'
支持:
ignorewarnthrow
推荐:
- 开发期用
warn或throw
redispatch 怎么配
当某个 importer 改写了 MessageText,是否允许重新分发。
redispatch: {
maxDepth: 3
}
典型场景:
- 任务系统把
/任务 签到翻译成真实命令,再继续走后续路由