UNPKG

@shangxueink/koishi-plugin-qq-markdown-button

Version:

[<ruby>**QQ机器人按钮菜单**<rp>(</rp><rt>点我查看使用说明</rt><rp>)</rp></ruby>](https://www.npmjs.com/package/@shangxueink/koishi-plugin-qq-markdown-button) 自用小插件咪~ 使用json文件设置你的机器人菜单这样就不需要一堆配置项还很烧脑了。自用插件哦~

139 lines (117 loc) 3.73 kB
import fs from 'node:fs' import path from 'node:path' import { Session } from 'koishi' import { Config, MenuType } from './types' interface TemplatePaths { jsonFilePath: string markdownFilePath: string | null } function isRecord(value: unknown): value is Record<string, unknown> { return typeof value === 'object' && value !== null } function parseTemplateRef(templateRef: string): { type: MenuType, name: string } { const separatorIndex = templateRef.indexOf('/') if (separatorIndex <= 0 || separatorIndex >= templateRef.length - 1) { throw new Error(`模板引用格式无效:${templateRef}`) } const type = templateRef.slice(0, separatorIndex) const name = templateRef.slice(separatorIndex + 1) if (type !== 'json' && type !== 'markdown' && type !== 'raw') { throw new Error(`模板类型无效:${templateRef}`) } return { type, name } } function getTemplatePaths(baseDir: string, templateRef: string): TemplatePaths { const { type, name } = parseTemplateRef(templateRef) if (type === 'json') { return { jsonFilePath: path.join(baseDir, 'json', `${name}.json`), markdownFilePath: null, } } if (type === 'markdown') { return { jsonFilePath: path.join(baseDir, 'markdown', `${name}.json`), markdownFilePath: null, } } return { jsonFilePath: path.join(baseDir, 'raw', `${name}.json`), markdownFilePath: path.join(baseDir, 'raw', `${name}.md`), } } function getPlaceholderValue( key: string, variables: Record<string, unknown>, args: string[], ): string | undefined { if (/^\d+$/.test(key)) { const index = Number.parseInt(key, 10) return args[index] ?? 'undefined' } const paths = key.split('.') let current: unknown = variables for (const pathKey of paths) { if (!isRecord(current) || !(pathKey in current)) { return undefined } current = current[pathKey] } return current === undefined ? undefined : String(current) } function replacePlaceholders( data: unknown, variables: Record<string, unknown>, args: string[], ): unknown { if (typeof data === 'string') { return data.replace(/\$\{([^}]+)\}/g, (_, key: string) => { const value = getPlaceholderValue(key, variables, args) return value === undefined ? `\${${key}}` : value }) } if (Array.isArray(data)) { return data.map((item) => replacePlaceholders(item, variables, args)) } if (isRecord(data)) { const result: Record<string, unknown> = {} for (const [key, value] of Object.entries(data)) { result[key] = replacePlaceholders(value, variables, args) } return result } return data } export function buildMenuMessage( baseDir: string, templateRef: string, session: Session, config: Config, interactionId: string, args: string[], ): unknown { const { jsonFilePath, markdownFilePath } = getTemplatePaths(baseDir, templateRef) const rawJsonData = fs.readFileSync(jsonFilePath, 'utf-8') const variables: Record<string, unknown> = { INTERACTION_CREATE: interactionId, session, config, args, } if (markdownFilePath) { // 原生 markdown 先替换 md 文件中的占位符。 const markdownContent = fs.readFileSync(markdownFilePath, 'utf-8') variables.markdown = replacePlaceholders(markdownContent, variables, args) } const rawJsonObject: unknown = JSON.parse(rawJsonData) const replacedJsonObject = replacePlaceholders(rawJsonObject, variables, args) if (isRecord(replacedJsonObject)) { // 根据会话类型清理互斥字段。 if (session.messageId) { delete replacedJsonObject.event_id } else { delete replacedJsonObject.msg_id } } return replacedJsonObject }