Run separate functions in node.js file from terminal - javascript

I have a javascript file the that I'm running some node tasks in, and would like to be able to run them separately based on the terminal command I trigger.
For instance, my nodejs file myFile code could look like this:
const mysql = require('mysql');
const fs = require('fs');
const getDbData = () => {
...
...
}
const fileTransform = () => {
file transformation functionality
}
I'd like to be able to run each function separately, so that I can say node myFile.js getDbData in terminal. Do I need to export each of the functions to be able to do this?

You can supply command-line arguments to your script on the node command line. You receive them in the process.argv array. Your arguments start at index 2 (0 is the full path to node, 1 is the full path to your script).
So for instance:
switch (process.argv[2]) {
case "getData":
getData();
break;
case "etlData":
etlData();
break;
// ...
}
Note that it's true that your arguments start at index 2 even if a Node argument precedes your script on the actual command line. For instance:
node --use-strict your-script.js
...will still have the full path to node in process.argv[0] and the full path to your script in process.argv[1]. The --use-strict argument isn't in the array at all.
Or you can put your functions on an object and use the argument as a key:
function getData() {
// ...
}
function getData() {
// ...
}
const functions = {
getData,
etlData
};
const fn = functions[process.argv[2]] || () => { console.log("Invalid option"); };
fn();

Try using process.argv.
https://stackabuse.com/command-line-arguments-in-node-js/
parse the command line arguments and, for example, evaluate them with eval()

Related

node.js using nested functions from different files

I wanted to write a understandable code in node.js, so I want to put some functions, which are used very often, into other node.js files, and access them from there.
So I get a function, which calls a function from another node.js file and in this other node.js file, also another one is called.
Important to know, if I put all in one file, the code works, so it should be an issue with module export and using functions in another file.
I have one file, getting quotes from a decentralised exchange. Looking like this (quoter_uni_v2.js):
module.exports = function quotes_uni_v2(tokenIn, tokenOut, amountIn, router) {
const quotedAmountOut = router.getAmountsOut(amountIn.toString(), [
tokenIn,
tokenOut,
]);
return quotedAmountOut;
};
And I am importing this function in my second helper file (quotes_5.js) (It is splitted in two files, because in the second one I have to call the function multiple times):
var quotes_uni_v2 = require("./quotes_uni_v2");
module.exports = async function (router1, router2, route, amount_wei) {
console.log(route);
var amount_Out = await quotes_uni_v2.quotes_uni_v2(
route[1],
route[2],
amount_wei,
router1
);
...
return (
Math.round(ethers.utils.formatEther(amount_Out[1].toString()) * 100) / 100
);
};
After that I try to call the function in my main.js:
const quotes_uni_v2 = require("./quotes_uni_v2");
const quotes_5 = require("./quotes_5");
async function calc(route) {
amountOut = await new quotes_5(
quickswap_router,
sushiswap_router,
route,
amount_wei
);
return amountOut;
};
But calling the quotes function does not work... The error is:
TypeError: quotes_5 is not a constructor...
Can someone help me?
Thanks!

Asynchronous recursive JavaScript function returns same value and terminates abruptly

Every time I run the following function, I expect it to output the different paths embedded in my composer.json file and then perform this recursively for each package. However, it just gives me the same result over and over again. Please what am I missing here?
const packageComposer = async (node) => {
node = node ? __dirname : node;
let composer = fs.readFileSync(node + '/composer.json', 'utf8');
let dependencies = Object.keys(JSON.parse(composer).require);
console.log(node + '/composer.json');
dependencies.forEach(key => {
let dependency = key.split('/');
let dir = node + '/vendor/' + dependency[0] + '/' + dependency[1];
if (fs.existsSync(dir)) {
packageComposer(dir);
}
});
}
Composer.json file looks like:
{
"require": {
"php": ">=7.2",
"alek13/slack": "^2.1",
"composer/installers": "^1.7",
"htmlburger/carbon-fields": "^3.3"
}
}
Console output:
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
/Users/user/Desktop/github/plugin-folder/composer.json
RangeError: Maximum call stack size exceeded
Exception in PromiseRejectCallback:
/Users/user/Desktop/github/plugin-folder/gulpfile.js:59
}
I was wondering why your console output never shows a path with /vendor in it because your recursive logic intends to create a path that has /vendor in it. Then, I realized, that's because this logic:
node = node ? __dirname : node;
is backwards and will always select __dirname when you pass a value for node. So, every recursive call ends up using the same value for node and thus an infinite loop that eventually overflows the stack.
Instead, you want this:
node = node ? node : __dirname;
The MDN description for the ternary operator is this:
condition ? exprIfTrue : exprIfFalse
Another way to do this is to use default parameters and let the JS engine supply a value when nothing is passed and write is this way:
const packageComposer = async (node = __dirname) => {
...
};
For any further debugging, I might suggest this cleaned up version with logging that lets you follow where it goes:
function packageComposer(node = __dirname) {
// read and parse composer.json using require()
const filename = path.join(node, 'composer.json');
console.log(`About to read ${filename}`);
let composer = require(filename);
const dependencies = Object.keys(composer.require);
console.log("Found dependencies", dependencies);
for (const key of dependencies) {
const pieces = key.split("/");
const dir = path.join(node, 'vendor', dependency[0], dependency[1]);
if (fs.existsSync(dir)) {
console.log(`Calling packageComposer(${dir}) recursively`);
packageComposer(dir);
}
}
}
As I said in my comments, a couple things seem odd here. You do key.split("/") to get the pieces of a key such as "alek13/slack", then you immediately put them back together again to reconstruct "alek13/slack" again. Not sure why you're doing that or what you expect to happen when the keys can't be split and you've got a key like "php" that doesn't contain a "/".

Netlify Serverless Function returning 404

I am trying to set up a simple serverless function on Netlify just to test out usage of environment variables. I have defined the following two environment variables in Netlify for my site:
Variable Name
Value
ALPHABET_SEPARATION
2
CHARS_BETWEEN
3
I have also updated my functions directory as follows:
Functions directory: myfunctions
I am using continuous deployment from github. As I do not know the use of npm at present and finding it convenient to directly test the production deploy, I have defined a subdirectory called myfunctions inside my root directory and have placed my javascript file containing the "serverless" function inside it on my local machine. I have built in logic so that the "serverless" function gets called only when a "netlify" flag is set, otherwise, an alternate function gets executed client-side. Basically it works as follows:
const deploy = "netlify" //Possible valid values are "local" and "netlify"
async function postRandomString() {
const stringToUpdate = "THISISATESTSTRING"
var stringToPost = "DUMMYINITIALVALUE";
if (deploy === "local") {
stringToPost = updateString(stringToUpdate); //updateString is a function defined elsewhere and executes client-side;
}
else if (deploy === "netlify") {
const config = {
method: 'GET',
headers: {
'Accept': 'application/json',
}
};
const res = await fetch(`myfunctions/serverUpdateString?input=${stringToUpdate}`, config);
const data = await res.json();
stringToPost = data.retVal;
console.log(data.retVal);
}
else {
stringToPost = "##ERROR##";
}
postString(stringToPost); //postString is a function defined elsewhere and executes client-side;
}
The serverless function file serverUpdateString.js is coded as follows (it basically sets a character at a certain position (determined by CHARS_BETWEEN) in the string to an alphabetical character which is a certain number (determined by ALPHABET_SEPARATION) of places in the alphabet after the first character of the string (don't ask why - the point is that it never even receives/handles the request):
exports.handler = async function (event) {
const { CHARS_BETWEEN, ALPHABET_SEPARATION } = process.env;
const charsBetween = CHARS_BETWEEN;
const alphabetSeparation = ALPHABET_SEPARATION;
const initString = event.queryStringParameters.input;
const rootUnicode = initString.charCodeAt(0);
const finalUnicode = "A".charCodeAt(0) + (rootUnicode - "A".charCodeAt(0) + alphabetSeparation) % 26;
const finalChar = String.fromCharCode(finalUnicode);
const stringArray = initString.split("");
stringArray[charsBetween + 1] = finalChar;
const stringToReturn = stringArray.join("");
const response = {
statusCode: 200,
retVal: stringToReturn,
}
return JSON.stringify(response);
}
When I run it, I get a 404 error for the GET request:
In the above image, script.js:43 is the line const res = await fetch(myfunctions/serverUpdateString?input=ATESTSTRIN, config); in the calling file, as shown in the first code block above.
What am I doing incorrectly? Surely Netlify should be able to pick up the serverless function file given that I have specified the folder alright and have placed it at the right place in the directory structure? I have given the whole code for completeness but the problem seems quite elementary. Look forward to your help, thanks.
I got assistance from Netlify forums. Basically the following changes needed to be made:
The fetch request -- line 43 in the calling code (script.js) -- needed to be changed to
const res = await fetch(`https://netlifytestserverless.netlify.app/.netlify/functions/serverUpdateString?input=${stringToUpdate}`, config);
The return statement in the lambda function needed to be changed to:
const response = {
statusCode: 200,
body: JSON.stringify(stringToReturn),
}
Other minor changes such as using parseInt with the environment variables.
The code works now.

Passing multiple parameters to NodeJS callback using export module

Scenarios 1:
I have two file in my atom project weather.js and exmaple.js and weather is using export module to export everything to example.js and in turn example.js is using require module
my weather.js
var request = require('request');
module.exports= function(justAnothercallback)
{
justAnothercallback('This is from weather');
}
myExample.js
var fromWeather = require('./weather.js');
fromWeather(function(weather){
console.log(weather);
});
If I do Node myExample.js the output is :
This is from weather
Scenarios 2:
Now I just pass one more callback in my weather.js
module.exports= function(justAnothercallback, SecondCallback) {
justAnothercallback('This is from weather');
SecondCallback('This is second callback)');
}
And my example.js is modified to accommodate the second callback function !!
var fromWeather = require('./weather.js');
fromWeather(function(weather, anotherfunc){
console.log(weather);
console.log(anotherfunc);
});
From the terminal we get :
/>node example-callback.js
This is from weather
undefined
/Users/NodeCourse/async/weather.js:7
SecondCallback('This is second callback)');
^
TypeError: SecondCallback is not a function
at module.exports (/Users/oogway/NodeCourse/async/weath
My question is are they not the same , I just added one more callback and it barfed !! why !!?? but it works fine if I pass just one callback ..
Please help one this .
In your code here, you are only passing one callback with two parameters
var fromWeather = require('./weather.js');
fromWeather(function(weather, anotherfunc){
console.log(weather);
console.log(anotherfunc);
});
This is what two callbacks would look like
var fromWeather = require('./weather.js');
fromWeather(function(){
console.log('Hello from callback 1');
}, function(){
console.log('Hello from callback 2');
});

async from dynamically generated array of functions nodeJs

So im working on a nodejs task that runs update tasks from cli
a snippet of my code
var
npm,
grunt,
async,
path,
which,
color,
isRoot,
progressBar,
EventEmitter,
exec,
utils,
format;
function loadDependencies() {
npm = require('npm');
grunt = require('grunt');
async = require('async');
path = require('path');
which = require('which');
color = require('cli-color');
isRoot = require('is-root');
progressBar = require('progress');
EventEmitter = require("events").EventEmitter;
exec = require('child_process').exec;
utils = require('../utils');
format = require('util').format
}
// Expose my module
module.exports = update;
function update(args, options, callback, ee){
//Load all my deps
loadDeps();
// Create my array
var taskCollection = [];
// Convert the update object with its functions into an array
for(var tasks in update){
taskCollection.push('update.' + tasks);
}
**After playing around I decided to try adding the following array here **
taskCollection = [update.one, update.two];
And it ran the tasks as it should so I can now only assume its how im making my array
//And this is were im stuck *
async.series(taskCollection,
function(err,result){
console.log(error);
console.log(result);
});
}
update.one = function(callback){
callback(null, 'Update One Complete);
}
update.two = function(callback){
callback(null, 'Update Two Complete);
}
Now the idea is that the list of tasks for async to run is automatically populated from my update object, meaning that anything like this
update.bower = function(){}
update.grunt = function(){}
will be run by async but other tasks like
var getVersion = function(){}
Wont the problem comes when I want to run async on the array of tasks Ive created I keep getting the error task() is not a function
Im trying to use
async.series(taskCollection, finish);
and some sort of variation of
async.each(taskCollection);
The ultimate goal will be that a progress bar will be added and so on the callback for each function will call progress.tick() with the number of ticks being automatically counted from the list of tasks
Whats the best way forward?
which async (NodeJs Version) task is best series because i want them in order each as they are an array of functions ?
Thanks in advance banging my head against the wall
Updated!!
The Error is generated from async.js:718 and says
task(_restParam(function (err,args))) {
^
TypeError: task is not a function
I was passing async an array of strings rather than objects.
Consider the following:
console.log(update);
// And you get
{[Function: update] one: [Function], two [Function]}
So in my above code
// Translation - For all the keys in the update object
for(var tasks in update){
// push that key as a string :(
taskCollection.push('update.' + tasks);
}
Update the for to the following:
for (var obj in tasks){
taskCount.push(obj);
taskCollection.push(tasks[obj]);
}
and now taskCount will produce an array of the function names
and taskCollection will work when passed to async :)

Categories

Resources