UNPKG

@kotori-bot/core

Version:
192 lines (191 loc) 8.27 kB
/** * @Package @kotori-bot/core * @Version 1.7.0 * @Author Arimura Sena <me@hotaru.icu> * @Copyright 2024-2025 Hotaru. All rights reserved. * @License BAN-ZHINESE-USING * @Link https://github.com/kotorijs/kotori * @Date 17:26:09 */ "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var utils_exports = {}; __export(utils_exports, { Decorators: () => Decorators, default: () => utils_default }); module.exports = __toCommonJS(utils_exports); var import_reflect_metadata = require("reflect-metadata"); var import_fluoro = require("fluoro"); var import_tsukiko = __toESM(require("tsukiko")); var import_error = require("../utils/error"); var import_global = require("../global"); var import_node_path = require("node:path"); var import_fast_safe_stringify = __toESM(require("fast-safe-stringify")); class Decorators { static [import_global.Symbols.decorator] = /* @__PURE__ */ new Map(); static getMeta(target) { return Reflect.getMetadata( import_global.Symbols.modules, typeof target === "string" ? Decorators[import_global.Symbols.decorator].get(target) ?? {} : target ); } static setup(ctx) { ctx.on("literal_ready_module_decorator", (name, config) => Decorators.load(ctx, name, config)); } static load(ctx, target, config) { const Constructor = typeof target === "string" ? Decorators[import_global.Symbols.decorator].get(target) : target; if (!Constructor) return false; const meta = Decorators.getMeta(Constructor); if (!meta) return false; const { name } = meta; if (meta.lang) ctx.i18n.use(meta.lang); let configHandle = config; if (meta.schema) { const result = meta.schema.parseSafe(config); if (!result.value) throw new import_error.ModuleError(`config format of module ${name} is error: ${result.error.message}`); configHandle = result.data; } const childCtx = ctx.extends(name); for (const identity of meta.inject) { const serviceData = Array.from(ctx[import_fluoro.Tokens.container]).find( ([, service]) => service instanceof import_fluoro.Service && service.identity === identity ); if (serviceData) childCtx.inject(serviceData[0]); } const plugin = new Constructor(childCtx, configHandle); const bound = (fn, isStatic) => fn.bind(isStatic ? Constructor : plugin); for (const [fn, options, isStatic] of meta.events) { childCtx[options.isOnce ? "once" : "on"](options.type, bound(fn, isStatic)); } for (const [fn, options, isStatic] of meta.midwares) { childCtx.midware(bound(fn, isStatic), options.priority); } for (const [fn, options, isStatic] of meta.commands) { const oldCmd = childCtx.command(options.template, { ...options, action: bound(fn, isStatic) }); let cmd = oldCmd; for (const option of JSON.parse((0, import_fast_safe_stringify.default)(options.options ?? []))) cmd = cmd.option(option[0], option[1]); childCtx[import_global.Symbols.command].delete(oldCmd); childCtx[import_global.Symbols.command].add(cmd); } for (const [fn, options, isStatic] of meta.regexps) { childCtx.regexp(options.match, bound(fn, isStatic)); } for (const [fn, options, isStatic] of meta.tasks) { childCtx.task(options, bound(fn, isStatic)); } const params = { instance: { inject: meta.inject, name, config: configHandle, default: Constructor } }; ctx.emit("ready_module", params); return true; } pkgName; error(message = "plugin not decorated") { return new import_error.DevError(`${message} at module ${this.pkgName}`); } getMeta(target) { const value = "prototype" in target ? target : target.constructor; let meta = Decorators.getMeta(value); if (meta) return meta; meta = { commands: [], events: [], midwares: [], inject: [], regexps: [], name: "unknown", tasks: [] }; Reflect.defineMetadata(import_global.Symbols.modules, meta, value); return meta; } constructor(pkgName) { this.pkgName = pkgName; } import = (target) => { if (Decorators[import_global.Symbols.decorator].has(this.pkgName)) throw this.error("plugin already decorated"); const meta = this.getMeta(target); meta.name = this.pkgName; Decorators[import_global.Symbols.decorator].set(this.pkgName, target); }; lang = (target, name) => { const meta = this.getMeta(target); const result = import_tsukiko.default.Union(import_tsukiko.default.String(), import_tsukiko.default.Array(import_tsukiko.default.String())).parseSafe(target[name]); if (!result.value) throw this.error("lang must be string or string[]"); meta.lang = (0, import_node_path.resolve)(...typeof result.data === "string" ? [result.data] : result.data); }; inject = (target, name) => { const meta = this.getMeta(target); const result = import_tsukiko.default.Array(import_tsukiko.default.String()).parseSafe(target[name]); if (!result.value) throw this.error(`inject must be string[] at ${this.pkgName}`); meta.inject = result.data; }; schema = (target, name) => { const meta = this.getMeta(target); const value = target[name]; if (!(value instanceof import_tsukiko.Parser)) throw this.error("schema must be Parser"); meta.schema = value; }; on(options) { return (target, key) => { const meta = this.getMeta(target); const fn = target[key]; if (typeof fn !== "function") throw this.error("event callback must be function"); meta.events = [...meta.events ?? [], [fn, options, "prototype" in target]]; }; } midware(options = {}) { return (target, key) => { const meta = this.getMeta(target); const fn = target[key]; if (typeof fn !== "function") throw this.error("middlewares callback must be function"); meta.midwares = [...meta.midwares ?? [], [fn, options, "prototype" in target]]; }; } command(options) { return (target, key) => { const meta = this.getMeta(target); const fn = target[key]; if (typeof fn !== "function") throw this.error("command callback must be function"); meta.commands = [...meta.commands ?? [], [fn, options, "prototype" in target]]; }; } regexp(options) { return (target, key) => { const meta = this.getMeta(target); const fn = target[key]; if (typeof fn !== "function") throw this.error("regexp callback must be function"); meta.regexps = [...meta.regexps ?? [], [fn, options, "prototype" in target]]; }; } task(options) { return (target, key) => { const meta = this.getMeta(target); const fn = target[key]; if (typeof fn !== "function") throw this.error("task callback must be function"); meta.tasks = [...meta.tasks ?? [], [fn, options, "prototype" in target]]; }; } } var utils_default = Decorators; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Decorators });