"use strict";
// Context.ts - Context for commands (noud02)
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const Eris = require("eris");
const tslint = require("tslint");
const ts = require("typescript");
const vm = require("vm");
/**
* Context class
*
* @export
* @class Context
*/
class Context {
constructor(shard, msg, prefix, command, flags, args) {
this.shard = shard;
this.msg = msg;
this.prefix = prefix;
this.command = command;
this.flags = flags;
this.args = args;
/**
* Message author
* @see https://abal.moe/Eris/docs/User
*
* @type {Eris.User}
*/
this.author = this.msg.author;
/**
* Channel the message was sent in
* @see https://abal.moe/Eris/docs/Channel
* @see https://abal/moe/Eris/docs/GuildChannel
* @see https://abal.moe/Eris/docs/PrivateChannel
*
* @type {(Eris.GuildChannel | Eris.PrivateChannel | Eris.GroupChannel)}
*/
this.channel = this.msg.channel;
/**
* Channel mentions in the message
*
* @type {(string[] | undefined)}
*/
this.channelMentions = this.msg.channelMentions;
/**
* Content of the message
*
* @type {(string | undefined)}
*/
this.content = this.msg.content;
/**
* Embeds on the message
*
* @type {Eris.Embed[]}
*/
this.embeds = this.msg.embeds;
/**
* Clean message content (<@id> -> @username)
*
* @type {(string | undefined)}
*/
this.cleanContent = this.msg.cleanContent;
/**
* Guild the message was sent in
* @see https://abal.moe/Eris/docs/Guild
*
* @type {(Eris.Guild | undefined)}
*/
this.guild = this.msg.channel instanceof Eris.GuildChannel ? this.msg.channel.guild : undefined;
/**
* Member that sent the message
* @see https://abal.moe/Eris/docs/Member
*
* @type {(Eris.Member | undefined)}
*/
this.member = this.msg.member;
/**
* User mentions in the message
*
* @type {Eris.User[]}
*/
this.mentions = this.msg.mentions;
/**
* When the message was sent
*
* @type {number}
*/
this.timestamp = this.msg.timestamp;
/**
* When the message was last edited
*
* @type {(number | undefined)}
*/
this.editedTimestamp = this.msg.editedTimestamp;
/**
* Role mentions in the message
*
* @type {string[]}
*/
this.roleMentions = this.msg.roleMentions;
/**
* Message content without flags
*
* @type {string}
*/
this.suffix = this.flags._.join(" ");
}
/**
* Sends a message to the channel the message was sent in
* @example ctx.send("a", "b", "nya") // a b nya
*
* @param {...any[]} args Content to send
* @returns {Promise<Eris.Message>}
*/
send(...args) {
return this.msg.channel.createMessage(args.join(" "));
}
/**
* Send a message like you normally would in Eris
*
* @see https://abal.moe/Eris/docs/Channel#function-createMessage
*
* @param {Eris.MessageContent} content Content to send
* @param {Eris.MessageFile} [file] File to send
* @returns {Promise<Eris.Message>}
*/
createMessage(content, file) {
return this.msg.channel.createMessage(content, file);
}
/**
* Sends a codeblock
*
* @example ctx.sendCode("ts", "const nya: Nya<awoo> = new Nya<awoo>()")
*
* @param {string} type Code language
* @param {...any[]} code Code to send
* @returns {Promise<Eris.Message>}
*/
sendCode(type, ...code) {
return this.msg.channel.createMessage(`\`\`\`${type}\n${code.join(" ")}\`\`\``);
}
/**
* Advanced (typescript) eval, linter included.
*
* @example const myEval = ctx.eval("interface IREEE { bool: boolean; }; const myREEE: IREEE = { bool: true }; myREEE;").eval // myEval = { bool: true }
*
* @param {string} code Code to run
* @param {map} customProps Custom properties to include in the eval context
* @returns {Promise<any>}
*/
eval(code, customProps) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const builtins = require("repl")._builtinLibs;
const context = vm.createContext();
for (const builtin of builtins) {
Object.defineProperty(context, builtin, {
get() {
context[builtin] = require(builtin);
return require(builtin);
},
set(val) {
delete context[builtin];
context[builtin] = val;
},
configurable: true,
});
}
Object.defineProperty(context, "process", {
get() {
context.process = process;
return process;
},
set(val) {
delete context.process;
context.process = val;
},
configurable: true,
});
for (const prop of Object.keys(customProps)) {
Object.defineProperty(context, prop, {
get() {
context[prop] = customProps[prop];
return customProps[prop];
},
set(val) {
delete context[prop];
context[prop] = val;
},
configurable: true,
});
}
const compilerOptions = {
"target": ts.ScriptTarget.ES5,
"module": ts.ModuleKind.CommonJS,
"lib": ["es6"],
"allowJs": false,
"checkJs": false,
"removeComments": false,
"noEmit": false,
"importHelpers": true,
"downlevelIteration": true,
"isolatedModules": false,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": ts.ModuleResolutionKind.NodeJs,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"plugins": [
{
"name": "tslint-language-service",
},
],
};
const compilerHost = ts.createCompilerHost(compilerOptions);
const getSourceFile = compilerHost.getSourceFile;
compilerHost.getSourceFile = function (fn) {
if (fn === "eval.ts") {
return ts.createSourceFile(fn, `${code}\r\n`, ts.ScriptTarget.ES5, false);
}
return getSourceFile.apply(this, arguments);
};
let output = "";
compilerHost.writeFile = (_fn, txt) => output += txt;
const program = ts.createProgram(["eval.ts"], compilerOptions, compilerHost);
const linter = new tslint.Linter({
fix: false,
formatter: "json",
});
linter.lint("eval.js", `${code}\r\n`, tslint.Configuration.findConfiguration("tslint.json", "../../").results);
const errs = program.getSyntacticDiagnostics(program.getSourceFile("eval.ts"));
errs.concat(program.getSemanticDiagnostics(program.getSourceFile("eval.ts")));
errs.concat(program.getDeclarationDiagnostics(program.getSourceFile("eval.ts")));
program.emit();
const out = yield vm.runInContext(output, context);
return {
eval: out,
ts: {
errs,
program,
},
tslint: linter.getResult(),
};
});
}
}
exports.Context = Context;