diff --git a/packages/cli/src/worker/utils.ts b/packages/cli/src/worker/utils.ts index 123c2fd18c..e0f89a31a4 100644 --- a/packages/cli/src/worker/utils.ts +++ b/packages/cli/src/worker/utils.ts @@ -1,13 +1,72 @@ -import { Context } from 'koishi' +import { Context, makeArray, MaybeArray } from 'koishi' interface Modifier { + $filter?: Selection $isolate?: string[] } +const selectors = ['user', 'guild', 'channel', 'self', 'private', 'platform'] as const + +export type SelectorType = typeof selectors[number] +export type SelectorValue = boolean | MaybeArray +export type BaseSelection = { [K in SelectorType]?: SelectorValue } + +interface Selection extends BaseSelection { + and?: Selection[] + or?: Selection[] + not?: Selection +} + +export function select(root: Context, options: Selection) { + let ctx = root + + // basic selectors + for (const type of selectors) { + const value = options[type] + if (value === true) { + ctx = ctx[type]() + } else if (value === false) { + ctx = ctx.exclude(ctx[type]()) + } else if (value !== undefined) { + // we turn everything into string + ctx = ctx[type](...makeArray(value).map(item => '' + item)) + } + } + + // intersect + if (options.and) { + for (const selection of options.and) { + ctx = ctx.intersect(select(root, selection)) + } + } + + // union + if (options.or) { + let ctx2: Context = ctx.never() + for (const selection of options.or) { + ctx2 = ctx2.union(select(root, selection)) + } + ctx = ctx.intersect(ctx2) + } + + // exclude + if (options.not) { + ctx = ctx.exclude(select(root, options.not)) + } + + return ctx +} + export function patch(ctx: Context, config: Modifier) { config ||= {} const parent = Object.getPrototypeOf(ctx) + if (config.$filter) { + ctx.filter = parent.intersect(select(ctx.any(), config.$filter)).filter + } else { + delete ctx.filter + } + const oldMapping = { ...ctx }.mapping || {} if (config.$isolate) { ctx.mapping = parent.isolate(config.$isolate).mapping diff --git a/packages/core/src/selector.ts b/packages/core/src/selector.ts index 0819dea678..b0a89e6ab4 100644 --- a/packages/core/src/selector.ts +++ b/packages/core/src/selector.ts @@ -1,4 +1,4 @@ -import { Dict, Logger, makeArray, MaybeArray, remove } from '@koishijs/utils' +import { Dict, Logger, remove } from '@koishijs/utils' import { Context, Events } from 'cordis' import { Channel } from './database' import { Session } from './protocol/session' @@ -17,18 +17,6 @@ declare module 'cordis' { export type Filter = (session: Session) => boolean -const selectors = ['user', 'guild', 'channel', 'self', 'private', 'platform'] as const - -export type SelectorType = typeof selectors[number] -export type SelectorValue = boolean | MaybeArray -export type BaseSelection = { [K in SelectorType as `$${K}`]?: SelectorValue } - -interface Selection extends BaseSelection { - $and?: Selection[] - $or?: Selection[] - $not?: Selection -} - export namespace SelectorService { export interface Delegates { logger(name: string): Logger @@ -137,46 +125,6 @@ export class SelectorService { return property(this.caller.exclude(property(this.caller, 'guildId')), 'userId', ...values) } - select(options: Selection) { - let ctx: Context = this.caller - - // basic selectors - for (const type of selectors) { - const value = options[`$${type}`] as SelectorValue - if (value === true) { - ctx = ctx[type]() - } else if (value === false) { - ctx = ctx.exclude(ctx[type]()) - } else if (value !== undefined) { - // we turn everything into string - ctx = ctx[type](...makeArray(value).map(item => '' + item)) - } - } - - // intersect - if (options.$and) { - for (const selection of options.$and) { - ctx = ctx.intersect(this.select(selection)) - } - } - - // union - if (options.$or) { - let ctx2: Context = this.caller - for (const selection of options.$or) { - ctx2 = ctx2.union(this.select(selection)) - } - ctx = ctx.intersect(ctx2) - } - - // exclude - if (options.$not) { - ctx = ctx.exclude(this.select(options.$not)) - } - - return ctx - } - before(name: K, listener: BeforeEventMap[K], append = false) { const seg = (name as string).split('/') seg[seg.length - 1] = 'before-' + seg[seg.length - 1]