@kotori-bot/core
Version:
Kotori Core
322 lines (321 loc) • 10.3 kB
JavaScript
/**
* @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 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
});