Skip to content

Commit

Permalink
fix: 更新消息解析规则
Browse files Browse the repository at this point in the history
  • Loading branch information
lc-cn committed Mar 2, 2024
1 parent c1fdd57 commit 539f70e
Show file tree
Hide file tree
Showing 16 changed files with 382 additions and 494 deletions.
19 changes: 19 additions & 0 deletions core/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import { Message } from '@/message';
import path from 'path';
import * as process from 'process';
import { getLogger, Logger } from 'log4js';
import { Dict } from '@/types';

export type AdapterBot<A extends Adapter> = A extends Adapter<infer B> ? B : unknown;
export type AdapterReceive<A extends Adapter> = A extends Adapter<infer B, infer R> ? R : unknown;
export type Element = {
type: string;
data: Dict;
};
export class Adapter<I extends object = object, M = {}> extends EventEmitter {
bots: Adapter.Bot<I>[] = [];
elements: Element[] = [];
app: App | null = null;
private _logger?: Logger;
get logger() {
Expand All @@ -32,6 +38,19 @@ export class Adapter<I extends object = object, M = {}> extends EventEmitter {
if (!bot) throw new Error(`未找到Bot:${bot_id}`);
return bot;
}
element(element: Element): this;
element(type: string, data: Dict): this;
element(...args: [Element] | [string, Dict]) {
const element =
typeof args[0] === 'string'
? {
type: args[0],
data: args[1]!,
}
: args[0];
this.elements.push(element);
return this;
}
mount(app: App, bots: App.BotConfig[]) {
this.emit('before-mount');
this.logger.level = app.config.logLevel;
Expand Down
9 changes: 9 additions & 0 deletions core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ export class App extends EventEmitter {
this.logger.level = config.logLevel;
this.handleMessage = this.handleMessage.bind(this);
this.on('message', this.handleMessage);
this.registerRender((template, message) => {
const elements = message?.adapter.elements || [];
for (const element of elements) {
template = template.replace(new RegExp(`^<${element.type}`), () => {
return '';
});
}
return template;
});
return new Proxy(this, {
get(target: App, key) {
if (Reflect.has(target.services, key)) return Reflect.get(target.services, key);
Expand Down
77 changes: 55 additions & 22 deletions core/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,58 @@ export class Message<AD extends Adapter> {
};
}
}
const wrapKV = Object.entries({
',': '_🤤_🤖_',
'&': '$amp;',
'<': '&lt;',
'>': '&gt;',
}).map(([key, value]) => ({ key, value }));
export function wrap(message: string) {
if (!message) return;
for (const { key, value } of wrapKV) {
message = message.replace(new RegExp(key, 'g'), value);

export function parseFromTemplate(template: string | MessageElem): MessageElem[] {
if (typeof template !== 'string') return [template];
const result: MessageElem[] = [];
const closingReg = /<(\S+)(\s[^\/]+)?\/>/;
const twinningReg = /<(\S+)(\s[^>]+)?>([^<]*)<\/\1>/;
while (template.length) {
const [_, type, attrStr = '', child = ''] = template.match(closingReg) || template.match(twinningReg) || [];
if (!type) break;
const isClosing = closingReg.test(template);
const matched = isClosing ? `<${type}${attrStr}/>` : `<${type}${attrStr}>${child}</${type}>`;
const index = template.indexOf(matched);
const prevText = template.slice(0, index);
if (prevText)
result.push({
type: 'text',
data: {
text: prevText,
},
});
template = template.slice(index + matched.length);
const attrArr = [...attrStr.matchAll(/\s([^=]+)(=[^/\s]+)?/g)];
const data = Object.fromEntries(
attrArr.map(([attr]) => {
const [key, ...values] = attr.split('=');
const value = values.join('=');
try {
return [key.trimStart(), JSON.parse(value.slice(1, -1))];
} catch {
return [key.trimStart(), JSON.parse(value)];
}
}),
);
result.push({
type: type,
data,
} as MessageElem);
}
return message;
}
export function unwrap(message: string) {
for (const { key, value } of wrapKV) {
message = message.replace(new RegExp(value, 'g'), key);
if (template.length) {
result.push({
type: 'text',
data: {
text: template,
},
});
}
return message;
return result;
}
type MessageElem = {
type: string;
data: Dict;
};
export namespace Message {
export type Render<T extends Message = Message> = (template: string, message?: T) => Promise<string> | string;
export type Segment = `<${string},${string}>` | string;
Expand Down Expand Up @@ -83,16 +116,16 @@ export namespace Message {
}
}
export const segment: Message.DefineSegment = function (type, data) {
return `<${type},${Object.entries(data)
return `<${type} ${Object.entries(data)
.map(([key, value]) => {
return `${key}=${wrap(JSON.stringify(value))}`;
return `${key}='${JSON.stringify(value)}'`;
})
.join()}>`;
.join(' ')}/>`;
} as Message.DefineSegment;
segment.text = text => text;
segment.face = (id: number) => `<face,id=${id}>`;
segment.image = (file: string) => `<image,file=${file}>`;
segment.at = user_id => `<at,user_id=${user_id}>`;
segment.face = (id: number) => `<face id='${id}'/>`;
segment.image = (file: string) => `<image src='${file}'/>`;
segment.at = user_id => `<at user_id='${user_id}'/>`;
type MessageSender = {
user_id?: string | number;
user_name?: string;
Expand Down
Loading

0 comments on commit 539f70e

Please sign in to comment.