From 037cc8b73fc45456b0348e5b095d85abc34a26fc Mon Sep 17 00:00:00 2001 From: Shigma Date: Thu, 2 Jan 2025 23:35:16 +0800 Subject: [PATCH] feat(satori): support Resource encode/decode API --- packages/core/src/session.ts | 9 ++--- packages/protocol/src/index.ts | 58 ++++++++++++++++++++++++++- packages/protocol/tests/index.spec.ts | 32 +++++++++++++++ yakumo.yml | 2 + 4 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 packages/protocol/tests/index.spec.ts diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index c0503f89..0b2b4d35 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -1,4 +1,4 @@ -import { Channel, Event, GuildMember, Login, Message, User } from '@satorijs/protocol' +import { Channel, Event, GuildMember, Login, Message, Resource, User } from '@satorijs/protocol' import { clone, defineProperty, isNullable } from 'cosmokit' import { Context, Service } from 'cordis' import { Bot } from './bot' @@ -114,10 +114,7 @@ export class Session { this.event.message.elements = isNullable(value) ? value : h.parse(value) if (this.event.message.elements?.[0]?.type === 'quote') { const el = this.event.message.elements.shift() - this.event.message.quote = { - ...el.attrs, - content: el.children.join(''), - } + this.event.message.quote = Resource.decode(el) } } @@ -151,7 +148,7 @@ export class Session { event.message.content = this.content delete event.message.elements if (event.message.quote) { - event.message.content = `${event.message.quote.content}` + event.message.content + event.message.content = Resource.encode('quote', event.message.quote) + event.message.content } } return event diff --git a/packages/protocol/src/index.ts b/packages/protocol/src/index.ts index f79cc41a..00246cfa 100644 --- a/packages/protocol/src/index.ts +++ b/packages/protocol/src/index.ts @@ -1,5 +1,5 @@ import Element from '@satorijs/element' -import { Dict } from 'cosmokit' +import { Dict, isNullable, pick } from 'cosmokit' export interface SendOptions { linkPreview?: boolean @@ -214,6 +214,62 @@ export interface User { isBot?: boolean } +export interface Resource { + attrs: (keyof K)[] + children: (keyof K)[] + content?: keyof K +} + +export function Resource(attrs: (keyof K)[], children: (keyof K)[] = [], content?: keyof K): Resource { + return { attrs, children, content } +} + +export namespace Resource { + export interface Definitions { + user: User + member: GuildMember + channel: Channel + guild: Guild + quote: Message + } + + const Definitions: { [K in keyof Definitions]: Resource } = { + user: Resource(['id', 'name', 'nick', 'avatar', 'isBot']), + member: Resource(['name', 'nick', 'avatar']), + channel: Resource(['id', 'type', 'name']), + guild: Resource(['id', 'name', 'avatar']), + quote: Resource(['id'], ['quote', 'user', 'member', 'channel'], 'content'), + } + + export function encode(type: K, data: Definitions[K]) { + const resource = Definitions[type] + const element = Element(type, pick(data, resource.attrs as any)) + for (const key of resource.children) { + if (isNullable(data[key])) continue + element.children.push(encode(key as any, data[key])) + } + if (resource.content && !isNullable(data[resource.content])) { + element.children.push(...Element.parse(data[resource.content] as string)) + } + return element + } + + export function decode(element: Element) { + const data: any = element.attrs + const resource = Definitions[element.type] + for (const key of resource.children) { + const index = element.children.findIndex((el) => el.type === key) + if (index === -1) continue + const [child] = element.children.splice(index, 1) + data[key] = decode(child) + } + if (resource.content && element.children.length) { + data[resource.content] = element.children.join('') + } + return data + } +} + export interface GuildMember { user?: User name?: string diff --git a/packages/protocol/tests/index.spec.ts b/packages/protocol/tests/index.spec.ts new file mode 100644 index 00000000..fe393e37 --- /dev/null +++ b/packages/protocol/tests/index.spec.ts @@ -0,0 +1,32 @@ +import Element from '@satorijs/element' +import { describe } from 'node:test' +import { Resource } from '../src' +import { expect, use } from 'chai' + +describe('@satorijs/protocol', () => { + describe('Resource', () => { + expect(Resource.encode('user', { + id: '1', + name: 'Alice', + }).toString()).to.equal('') + + expect(Resource.decode(Element.parse('')[0])).to.deep.equal({ + id: '1', + name: 'Alice', + }) + + expect(Resource.encode('quote', { + id: '1', + content: '
', + quote: { id: '2' }, + user: { id: '3' }, + }).toString()).to.equal('
') + + expect(Resource.decode(Element.parse('
')[0])).to.deep.equal({ + id: '1', + content: '
', + quote: { id: '2' }, + user: { id: '3' }, + }) + }) +}) diff --git a/yakumo.yml b/yakumo.yml index c2ca38b5..4a25bf72 100644 --- a/yakumo.yml +++ b/yakumo.yml @@ -23,3 +23,5 @@ name: yakumo/version - id: 16co8h name: yakumo/publish +- id: 4q41x7 + name: yakumo/test