UNPKG

@kotori-bot/core

Version:
322 lines (321 loc) 10.3 kB
/** * @Package @kotori-bot/core * @Version 1.7.2 * @Author Arimura Sena <me@hotaru.icu> * @Copyright 2024-2025 Hotaru. All rights reserved. * @License GPL-3.0 * @Link https://github.com/kotorijs/kotori * @Date 2026/2/14 15:50:13 */ "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 command_exports = {}; __export(command_exports, { Command: () => Command, default: () => command_default }); module.exports = __toCommonJS(command_exports); var import_minimist = __toESM(require("minimist")); var import_types = require("../types"); var import_error = require("../utils/error"); const requiredParamMatch = /<(\.\.\.)?(.*?)(:(.*?))?(=(.*?))?>/; const optionalParamMatch = /\[(\.\.\.)?(.*?)(:(.*?))?(=(.*?))?\]/; const defaultType = "string"; class Command { static handleDefaultValue(value, type) { if (type === "boolean") return value !== "false" && !!value; if (type === "number") { if (typeof value === "number") return value; if (value === true) return 1; if (value === false) return 0; const float = Number.parseFloat(value); const int = Number.parseInt(value); return float === int ? int : float; } return value.toString(); } static parseArgs(command) { const args = []; let current = ""; let inQuote = false; let quoteChar = null; let lastQuoteChar = null; for (let i = 0; i < command.length; i += 1) { let c = command[i]; if (inQuote) { if (c === quoteChar) { inQuote = false; quoteChar = null; } else if (c === "\\" && i + 1 < command.length) { i += 1; c = command[i]; if (c === '"' || c === "'") { current += c; } else { current += `\\${c}`; } } else { current += c; } } else if (c === '"' || c === "'") { inQuote = true; quoteChar = c; lastQuoteChar = c; } else if (c === " " && current) { args.push(current); current = ""; } else { current += c; } } if (inQuote || quoteChar) return { char: lastQuoteChar, index: command.lastIndexOf(lastQuoteChar) }; if (current) args.push(current); return args; } static run(input, data) { let starts = ""; for (const el of [data.root, ...data.alias]) { if (starts) continue; if (input.startsWith(`${el} `) || input === el) starts = el; } if (!starts) return new import_error.CommandError({ type: "unknown", input }); const opts = { string: [], boolean: [], alias: {} }; for (const option of data.options) { if (option.type === "string") opts.string.push(option.realname); else if (option.type === "boolean") opts.boolean.push(option.realname); opts.alias[option.realname] = option.name; } const arr = Command.parseArgs(input.slice(starts.length).trim()); if (!Array.isArray(arr)) return new import_error.CommandError({ type: "syntax", ...arr }); const result = (0, import_minimist.default)(arr, opts); const args = result._; const count = { expected: data.args.filter((el) => !el.optional).length, reality: args.length }; if (count.reality < count.expected) return new import_error.CommandError({ type: "arg_few", ...count }); count.expected = data.args.length; if ((data.args.length <= 0 || !data.args[data.args.length - 1].rest) && count.reality > count.expected) return new import_error.CommandError({ type: "arg_many", ...count }); let error; data.args.forEach((val, index) => { if (error || index > 0 && !args[index - 1]) return; if (!args[index] && val.default) { args[index] = val.default; return; } if (val.rest || !args[index]) return; args[index] = Command.handleDefaultValue(args[index], val.type); if (!Number.isNaN(args[index])) return; error = new import_error.CommandError({ type: "arg_error", expected: "number", reality: "string", index }); }); if (error) return error; const options = {}; for (const val of data.options) { if (!(val.realname in result)) continue; options[val.realname] = Array.isArray(result[val.realname]) ? result[val.realname][0] : result[val.realname]; options[val.realname] = Command.handleDefaultValue(options[val.realname], val.type); if (Number.isNaN(options[val.realname])) error = new import_error.CommandError({ type: "option_error", expected: "number", reality: "string", target: val.realname }); } if (error) return error; return { args: data.args.length > 0 && data.args[data.args.length - 1].rest ? args : args.slice(0, data.args.length), options }; } template; /** * Command meta data. * * @readonly */ meta = { root: "", alias: [], scope: "all", access: import_types.UserAccess.MEMBER, args: [], options: [], hide: false, shortcut: [] }; /** * Create a command instance * * @param template - Command template. * @param config - Command config. */ constructor(template, config) { this.template = template; this.meta = Object.assign(this.meta, config); this.parse(); } parse() { const [str, description] = this.template.trim().split(" - "); this.meta.description = description; const requiredIndex = str.indexOf(" <"); const optionalIndex = str.indexOf(" ["); if (requiredIndex === -1 && optionalIndex === -1) { this.meta.root = str.trim(); return; } if (requiredIndex !== -1 && (optionalIndex === -1 || requiredIndex < optionalIndex)) { this.meta.root = str.substring(0, requiredIndex).trim(); } else { this.meta.root = str.substring(0, optionalIndex).trim(); } const args = (0, import_minimist.default)(str.split(" "))._; for (const arg of args) { const current = this.meta.args[this.meta.args.length - 1]; if (current?.rest) continue; let result = optionalParamMatch.exec(arg); if (result) { if (!result[2]) continue; const type = import_types.commandArgTypeSignSchema.parseSafe(result[4]).value ? result[4] : defaultType; this.meta.args.push({ name: result[2], type, rest: !!result[1], optional: true, default: result[6] ? Command.handleDefaultValue(result[6], type) : void 0 }); } result = requiredParamMatch.exec(arg); if (!result || !result[2]) continue; if (!result[6] && current?.optional) continue; this.meta.args.push({ name: result[2], type: import_types.commandArgTypeSignSchema.parseSafe(result[4]).value ? result[4] : defaultType, rest: !!result[1], optional: false }); } } /** * Add command alias. * * @param alias - Command alias. * @returns Command instance */ alias(alias) { if (typeof alias === "string") this.meta.alias.push(alias); else this.meta.alias.push(...alias); return this; } /** * Add command shortcut. * * @param short - shortcut name * @returns Command instance */ shortcut(short) { if (typeof short === "string") this.meta.shortcut.push(short); else this.meta.shortcut.push(...short); return this; } /** * Set the message scope which command require. * * @param scope - Message scope. * @returns Command instance */ scope(scope) { this.meta.scope = scope; return this; } /** * Set the user access level which command require. * * @param access - User access level. * @returns Command instance */ access(access) { this.meta.access = access; return this; } /** * Add command option. * * @param name - Option name. * @param template - Option template. * @returns Command instance */ option(name, template) { const [str, description] = template.trim().split(" "); const [realname, type] = str.split(":"); this.meta.options.push({ realname, description, type: import_types.commandArgTypeSignSchema.parseSafe(type).value ? type : defaultType, name: name.charAt(0) }); return this; } /** * Set command action. * * @param callback - Command action. * @returns Command instance */ action(callback) { this.meta.action = callback; return this; } /** * Set command help text. * * @param text - Command help text. * @returns Command instance */ help(text) { this.meta.help = text; return this; } /** * Set command hide. * * @param isHide - Command hide. * @returns Command instance */ hide(isHide = true) { this.meta.hide = isHide; return this; } } var command_default = Command; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Command });