diff --git a/packages/koishi-core/src/context.ts b/packages/koishi-core/src/context.ts index 0d1212a84f..376e2dd51b 100644 --- a/packages/koishi-core/src/context.ts +++ b/packages/koishi-core/src/context.ts @@ -449,13 +449,8 @@ export class Context { async transformAssets(content: string, assets = this.assets) { if (!assets) return content - const urlMap: Record = {} - await Promise.all(segment.parse(content).map(async ({ type, data }) => { - if (!assets.types.includes(type as Assets.Type)) return - urlMap[data.url] = await assets.upload(data.url, data.file) - })) - return segment.transform(content, Object.fromEntries(assets.types.map((type) => { - return [type, (data) => segment(type, { url: urlMap[data.url] })] + return segment.transformAsync(content, Object.fromEntries(assets.types.map((type) => { + return [type, (data) => assets.upload(data.url, data.file)] }))) } diff --git a/packages/koishi-utils/src/segment.ts b/packages/koishi-utils/src/segment.ts index 8c9cc50c51..024cde6a14 100644 --- a/packages/koishi-utils/src/segment.ts +++ b/packages/koishi-utils/src/segment.ts @@ -20,6 +20,7 @@ export namespace segment { export type Chain = segment.Parsed[] export type Data = Record export type Transformer = string | ((data: Record, index: number, chain: Chain) => string) + export type AsyncTransformer = string | ((data: Record, index: number, chain: Chain) => string | Promise) export interface Parsed extends segment { data: Record @@ -44,8 +45,8 @@ export namespace segment { .replace(/&/g, '&') } - export function join(codes: segment[]) { - return codes.map(code => segment(code.type, code.data)).join('') + export function join(chain: segment[]) { + return chain.map(node => segment(node.type, node.data)).join('') } export interface FindOptions { @@ -91,6 +92,17 @@ export namespace segment { }).join('') } + export async function transformAsync(source: string, rules: Record) { + const chain = segment.parse(source) + const cache = new Map() + await Promise.all(chain.map(async (node, index, chain) => { + const transformer = rules[node.type] + if (!transformer) return + cache.set(node, typeof transformer === 'string' ? transformer : await transformer(node.data, index, chain)) + })) + return chain.map(node => cache.get(node) || segment(node.type, node.data)).join('') + } + export type Factory = (value: T, data?: segment.Data) => string function createFactory(type: string, key: string): Factory {