Normally I just add to the command files or the index file easily but it's starting to look messy. Recently I got this leveling system working
if (!levels[message.author.id]) {
levels[message.author.id] = {
level: 1,
exp: 0
}
}
// Gives random EXP
let randomExp = Math.floor(Math.random() * 5 + 5);
// Adds the random EXP to their current EXP
levels[message.author.id].exp += randomExp;
// Checks their EXP and changes their level
for (x = 0; x < expLevels.length; x++) {
if (levels[message.author.id].exp > expLevels[x]) {
levels[message.author.id].level = x + 1;
message.channel.reply(`congratulations! You reached level ${levels[message.author.id].level + 1}!`);
}
}
fs.writeFile('./levels.json', JSON.stringify(levels), err => {
if (err) console.error(err);
});
if (levels[authorMessage.author.id].level >= 10) {
message.member.roles.remove('720109209479413761');
message.member.roles.add('719058151940292659');
}
I would like to be able to put this into its own function and then call it in the "message" section for every time someone sends a message. Is that possible to do? Or no since I need to have access to the "message" variable?
I'm used to C++ with functions where it's much easier to deal with. Does anyone know if it's possible to code a bot in C++ or is there no support? If there is a way if someone can point me in the right direction to start please let me know. Otherwise I can easily stay with JS.
I'm not sure if a discord framework for C++ exists, probably but I'm not sure.
You can of course define a function somewhere and call it in the onMessage event.
There are two ways that you could do that.
In the same file
In another file
Functions in the same file.
You can declare a function and then pass arguments to that function. You don't need to declare the type of argument that is being passed here. Source
function leveling(message) { // here you can include all parameters that you might need
// the rest of your code
}
Once you have a function you can call it like this.
leveling(message); // here we pass the values we need to the function
Functions in a different file.
The concept is the same, however we need to export the function in order to use it somewhere else. There are two ways to do this, either export only one function or export all functions, in the case of a dedicated functions file this is the easier option.
Note: In this example I name the file functions.js and place it in the same directory as the file I require it from.
module.exports = {
// we need to declare the name first, then add the function
leveling: function (message) {
// the rest of your code
}
// here we can add more functions, divided by a comma
}
// if you want to export only one function
// declare it normally and then export it
module.exports = leveling;
Calling functions.
To use this function we need to require it in the file we want to use it in. Here we also have two options.
Either require the whole file and get the function from there
const myfunctions = require('./functions.js'); // this is the relative path to the file
// get the function via the new constant
myfunctions.leveling(message);
Or use Object destructuring to get only what you need from the exported functions.
const { leveling } = require('./functions.js');
leveling(message);
Both of these options provide advantages and disadvantages but in the end they both do the same.
Related
So I know the question is probably super confusing but basically I have a file in my node project that when importing one of the exports it will set the value of variable in the global scope as a getter. Basically this means that you can call the same value over and over again and get different results. For example:
magicIncrement.js:
let count = -1;
module.exports = {
get magicIncrement() {
Object.defineProperty(global, 'increment', {
get: () => {
count += 1;
return count;
},
});
},
};
index.js:
let { magicIncrement } = require('./magicIncrement');
console.log( 'increment:', increment );
const test = increment;
console.log('"test"s value doesn\'t change.')
console.log('test:', test);
console.log('test:', test);
setTimeout(() => {
console.log('...but "increment"s value always will')
console.log( 'increment:', increment );
}, 1010);
The result is that increment will increase every time the variable is called.
The issue is that the variable isn't recognized by the IDE since 'increment' technically doesn't exist as far as VSCode is aware. Is there any way to fix this issue?
P.S. I tried simply setting the export (in this example "magic increment") as the name of the global variable/getter (in this case "increment") but it seems like setting a variable in a file (like via destructing as done in index.js) simply cuts the link between global.[var name] and [var name].
When you're working in a module system and you're writing a script, you should generally try to work within the module system whenever possible. Only resort to global pollution when there's no other option.
Here, you can accomplish what you need by returning the getter on an exported object (not the global object):
let count = -1;
module.exports = {
get increment() {
count += 1;
return count;
}
};
const theIncrementModule = require('./magicIncrement');
console.log(theIncrementModule.increment);
console.log(theIncrementModule.increment);
But this sort of code is pretty confusing - when writing solid, maintainable code, you shouldn't try to deliberately hide the fact that a certain getter or property access is carrying out side-effects (such as incrementing a count variable). You can hide it behind abstractions, sure - but don't try to write confusing and tricky code (like having a getter on the global object) to hide it.
I am unable to use the same instance of an object in another java-script file using nodejs.
I'm working on a bot for telegram. Because the file gets large and chaotic, i would like to split the functions of my bot into a few extra js files. But i don't know any way how to share the same instance of an object between multiple javascript files.
///////////////////////8Ball File
const {eightBall} = require("./main");
const ballBot = myAwseomeBot;
function eightBall() {
ballBot.onText(/\/8ball/, (msg, callback) => {
let ranNum = Math.floor(Math.random() * 15) + 1;
const chatId = msg.chat.id;
const reply_to_message_id = msg.message_id;
console.log(ranNum);
switch (ranNum) {
case 1:
ballBot.sendMessage(chatId, "Ja");
break;
}
})
}
//main file
let myAwesomeBot = new TelegramBot(botToken, {polling:true});
exports.myAwesomeBot = myAwesomeBot;
ballBot.onText(/\/8ball/, (msg, callback) => {
^
TypeError: Cannot read property 'onText' of undefined
It isn't shown in your code here, but you probably have a cyclic dependency, where A requires B, and B requires A.
The simplest solution relevant to your use case is to define and implement commands for your bot in additional files, and let your bot file attach / consume them:
8ball.js
import { telegram stuff } from 'wherever';
export myCommand1 = {
pattern: /\/8ball/,
eventName: 'ontext',
callback: (msg, msgCallback) => { /* use "this" as if it were the bot instance */};
};
main.js
import .... from ....;
import { myCommand1 } from '8ball';
...
bot.onText(myCommand1.pattern, myCommand1.callback.bind(bot));
...
There are probably other bot class methods more suited for attaching generic event handlers/listeners, and also other methods of specifying your module exports, but the idea is that your command files don't need to import the bot file. I have not researched the telegram bot API so it may have some manner of delegating the bot instance when attaching an event handler. If so, use it!
Did you check that ballBot was defined?
Try to remove the brackets when requiring the main file. I would also suggest using the Singleton pattern if you want to share the same instance across your code.
Could it be that there is a typo on line 2? Should be
myAwesomeBot not myAwseomeBot.
const ballBot = myAwseomeBot;
I am working on supporting a REST API that literally has thousands of functions/objects/stats/etc., and placing all those calls into one file does not strike me as very maintainable. What I want to do is have a 'base' file that has the main constructor function, a few utility and very common functions, and then files for each section of API calls.
The Problem: How do you attach functions from other files to the 'base' Object so that referencing the main object allows for access from the subsections you have added to your program??
Let me try and illustrate what I am looking to do:
1) 'base' file has the main constructor:
var IPAddr = "";
var Token = "";
exports.Main = function(opts) {
IPAddr = opts.IPAddr;
Token = opts.Token;
}
2) 'file1' has some subfunctions that I want to define:
Main.prototype.Function1 = function(callback) {
// stuff done here
callback(error, data);
}
Main.prototype.Function2 = function(callback) {
// stuff done here
callback(error,data);
}
3) Program file brings it all together:
var Main = require('main.js');
var Main?!? = require('file1.js');
Main.Function1(function(err,out) {
if(err) {
// error stuff here
}
// main stuff here
}
Is there a way to combine an Object from multiple code files?? A 120,000 line Node.JS file just doesn't seem to be the way to go to me....not to mention it takes too long to load! Thanks :)
SOLUTION: For those who may stumble upon this in the future... I took the source code for Object.assign and back ported it to my v0.12 version of Node and got it working.
I used the code from here: https://github.com/sindresorhus/object-assign/blob/master/index.js and put it in a separate file that I just require('./object-assign.js') without assigning it to a var. Then my code looks something like this:
require('./object-assign.js');
var Main = require('./Main.js');
Object.assign(Main.prototype, require('./file1.js'));
Object.assign(Main.prototype, require('./file2.js'));
And all my functions from the two files show up under the Main() Object...too cool :)
At first each file works in its own scope, so all local variables are not shared.
However, as hacky approach, you may just add Main into global scope available everywhere by writing global.Main = Main right after you define it, please make sure that you require main file first in list of requires.
The better(who said?) approach is to extend prototype of Main later, but in this case you may need to update a lot of code. Just mix-in additional functionality into base class
file1.js
module.exports = {
x: function() {/*****/}
}
index.js
var Main = require('main.js');
Object.assign(Main.prototype, require('file1.js'));
Shure.
constructor.js
module.exports = function(){
//whatever
};
prototype.js
module.exports = {
someMethod(){ return "test";}
};
main.js
const Main = require("./constructor.js");
Object.assign( Main.prototype, require("./prototype.js"));
I would like to make use of a function called executeJavaScript() from the Electron webContents API. Since it is very close to eval() I will use this in the example.
The problem:
I have a decent sized script but it is contained in a template string.
Expanding this app, the script could grow a lot as a string.
I am not sure what the best practices are for this.
I also understand that eval() is dangerous, but I am interested in the principal of my question.
Basic eval example for my question:
// Modules
const fs = require('fs');
// CONSTANTS
const EXAMPLE_1 = 'EXAMPLE_1';
const EXAMPLE_2 = 'EXAMPLE_2';
const EXAMPLE_3 = 'EXAMPLE_3';
const exampleScriptFunction = require('./exampleScriptFunction');
const exampleScriptFile = fs.readFileSync('./exampleScriptFile.js');
// using direct template string
eval(`console.log(${EXAMPLE_1})`);
// using a method from but this doesnt solve the neatness issue.
eval(exampleScriptFunction(EXAMPLE_2));
// What I want is to just use a JS file because it is neater.
eval(`${exampleScriptFile}`);
exampleScriptFunction.js
module.exports = function(fetchType) {
return `console.log(${fetchType});`;
}
This will allow me to separate the script to a new file
what if I have many more then 1 variable???
exampleScriptFile.js:
console.log(${EXAMPLE_3});
This clearly does not work, but I am just trying to show my thinking.
back ticks are not present, fs loads as string, main file has back ticks.
This does not work. I do not know how else to show what I mean.
Because I am loading this will readFileSync, I figured the es6 template string would work.
This allows me to write a plain js file with proper syntax highlighting
The issue is the variables are on the page running the eval().
Perhaps I am completely wrong here and looking at this the wrong way. I am open to suggestions. Please do not mark me minus 1 because of my infancy in programming. I really do not know how else to ask this question. Thank you.
Assuming your source is stored in exampleScriptFile:
// polyfill
const fs = { readFileSync() { return 'console.log(`${EXAMPLE_3}`);'; } };
// CONSTANTS
const EXAMPLE_1 = 'EXAMPLE_1';
const EXAMPLE_2 = 'EXAMPLE_2';
const EXAMPLE_3 = 'EXAMPLE_3';
const exampleScriptFile = fs.readFileSync('./exampleScriptFile.js');
// What I want is to just use a JS file because it is neater.
eval(exampleScriptFile);
Update
Perhaps I wasn't clear. The ./exampleScriptFile.js should be:
console.log(`${EXAMPLE_3}`);
While what you're describing can be done with eval as #PatrickRoberts demonstrates, that doesn't extend to executeJavaScript.
The former runs in the caller's context, while the latter triggers an IPC call to another process with the contents of the code. Presumably this process doesn't have any information on the caller's context, and therefore, the template strings can't be populated with variables defined in this context.
Relevant snippets from electron/lib/browsers/api/web-contents.js:
WebContents.prototype.send = function (channel, ...args) {
// ...
return this._send(false, channel, args)
}
// ...
WebContents.prototype.executeJavaScript = function (code, hasUserGesture, callback) {
// ...
return asyncWebFrameMethods.call(this, requestId, 'executeJavaScript',
// ...
}
// ...
const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
return new Promise((resolve, reject) => {
this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
// ...
})
}
Relevant snippets from electron/atom/browser/api/atom_api_web_contents.cc
//...
void WebContents::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "WebContents"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
// ...
.SetMethod("_send", &WebContents::SendIPCMessage)
// ...
}
Currently I am just passing my fileNamePrefix like that:
let shortid = require('shortid');
let fileNamePrefix = shortid.generate();
module1.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f1.json`
module2.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f2.json`
module3.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f3.js
Which I think in not quite right, I might need to pass more things to my modules later on, so I want to avoid to pass that as function params.
What is the best way to approach that in nodejs?
Will global object like global.fileNamePrefix = shortid.generate(); will do in that case or would you approach that different? I just read that global is not good...
You can use either singleton approach or approach suggested by #Сергей Тертичный
Singleton :
//shortid.js
var fileSingleTon = module.exports = {
fileNamePrefix: null,
getFileNamePrefix: function() {
return fileSingleTon.fileNamePrefix || fileSingleTon.generate()
},
generate: function() {
console.log('generating..');
return fileSingleTon.fileNamePrefix = 'your_file_prefix';
}
}
//module1.js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
//module2/js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
and so on..
Even now you are calling require('./shortid').getFileNamePrefix(); multiple times, generate function is getting called only once.
Node Caching approach :
Consider you have shortid.js as following :
// A: block of code to do some manipulations
// B : module.exports = manipulation result.
So basically in node js "modules" core module which is responsible for giving us module.export functionality executes whatever is here above export(in abode example the part A) only for the first time and caches it even if you have required in in multiple other files. However, it only executes the functions or block of code in every require which is inside export. So you can use this approach where your A block will have login to generate fileNamePrefix and then B just returns it.
Just create module like that:
// unicname.js
let shortid = require('shortid');
let fileName = shortid.generate();
module.exports = {fname: fileName};
//module1.js
const {fname} = require('./unicname.js');
....
Since the node.js caching the modules the value will be calculated only one time so you can get same value in all your modules.