Nodejs - passing commander arguments to forever-monitor child process - node.js

I have this node cli script
#!/usr/bin/env node
const path = require('path');
const forever = require('forever-monitor');
const script = path.format({dir: __dirname, base: 'pager.js'});
const chalk = require('chalk');
const commander = require('commander');
commander.version('1.0.0')
.option('-m, --message', 'set awesome message')
.parse();
const args = commander.opts();
const header = `
+---------------------+
| Awesome v1.0 |
+---------------------+
`;
const child = new (forever.Monitor)(script, {
max: 2,
silent: false,
args: args
});
child.start();
child.on('start', (process) => {
console.log(chalk.magenta.bold(header));
});
child.on('restart', () => {
console.log(`Forever restarting script for ${child.times} time`);
});
child.on('exit:code', (code) => {
console.log(`Forever detected script exited with code ${code}`);
});
I want to integrate commander togive the user the ability to pass arguments that will be parsed and then passed to the child process that is running until terminal is closed with the help of forever-monitor npm package. At the moment I've tried to use commander inside the child process but without success, it will be ignored. I've then moved it inside my index.js code but I don't know how to pass the arguments to the child process. At the moment I get this error if I pass the parsed arguments to the args option of forever monitor
host:awesome dev$ node . -m 'Hello!'
/Users/dev/Desktop/awesome/node_modules/forever-monitor/lib/forever-monitor/monitor.js:130
this.args.unshift(script);
^
TypeError: this.args.unshift is not a function
at new exports.Monitor (/Users/dev/Desktop/awesome/node_modules/forever-monitor/lib/forever-monitor/monitor.js:130:15)
at Object.<anonymous> (/Users/dev/Desktop/awesome/index.js:20:15)
at Module._compile (node:internal/modules/cjs/loader:1108:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
at Module.load (node:internal/modules/cjs/loader:973:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)
at node:internal/main/run_main_module:17:47
Can anyone give me some help about?

forever-monitor: the args configuration option passed to forever-monitor expects an array.
'args': ['foo','bar']
Commander: program.opts() returns a regular javascript object which is a hash with the keys being the option names. program.args is an array of the parsed command-arguments with recognised options and option-values removed.
In Commander, also have a look at .allowUnknownOption() and passThroughOptions() so Commander allows unrecognised options on the command line. The default behaviour is to show an error for unrecognised options.

Related

trouble with modules in repl

i am having a hell of time trying to set up a custom repl app. I did a bunch of googling and managed to wrange the code below and got a working repl shell.
script.js
const repl = require("repl")
function evaluate(command, context, filename, callback) {
callback(null, command)
}
repl.start({
prompt: ": ",
eval: evaluate
});
so after getting this prototype working i decided to add a module to split the routing of the command processing. I made a tracker.js module and required it in my script.js
tracker.js
export default class Tracker {
static Process(command) {
console.log(command)
}
}
script.js added the require statement.
const repl = require("repl")
const Tracker = require("./tracker")
function evaluate(command, context, filename, callback) {
callback(null, command)
}
repl.start({
prompt: ": ",
eval: evaluate
});
after i reran this i got an error saying,
SyntaxError: Unexpected token 'export'
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Module.require (node:internal/modules/cjs/loader:1005:19)
at require (node:internal/modules/cjs/helpers:102:18)
at Object.<anonymous> (C:\Users\e212034\repository\repl\script.js:2:17)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
PS C:\Users\e212034\repository\repl>
so i went back to google and found some tips saying to add type:module to the package.json. so i did this and reran and now i get this error,
ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and 'C:\Users\e212034\repository\repl\package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///C:/Users/e212034/repository/repl/script.js:1:14
at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
PS C:\Users\e212034\repository\repl>
i tried changing the module to .mjs no luck. i tried changing the type to commonjs and the module to .cjs no luck on either.
any ideas on how to resolve this issue?

Await in NodeJS in script vs runkit [duplicate]

I have node 14.13.0, and even with --harmony-top-level-await, top-level await is not working.
$ cat i.js
const l = await Promise.new(r => r("foo"))
console.log(l)
$ node -v
v14.13.0
$ node --harmony-top-level-await i.js
/Users/karel/i.js:1
const l = await Promise.new(r => r("foo"))
^^^^^
SyntaxError: await is only valid in async function
at wrapSafe (internal/modules/cjs/loader.js:1001:16)
at Module._compile (internal/modules/cjs/loader.js:1049:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:791:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47
What am I doing wrong?
Top-level await only works with ESM modules (JavaScript's own module format), not with Node.js's default CommonJS modules. From your stack trace, you're using CommonJS modules.
You need to put "type": "module" in package.json or use .mjs as the file extension (I recommend using the setting).
For instance, with this package.json:
{
"type": "module"
}
and this main.js:
const x = await Promise.resolve(42);
console.log(x);
node main.js shows 42.
Side note: You don't need --harmony-top-level-await with v14.13.0. Top-level await is enabled by default in that version (it was enabled in v14.8.0).
T.J. Crowder answer is right, but I recommend changing all the .js to .mjs
For example, if you are working with NextJS like me, you will see a problem that files in the .next directory use CommonJS (.next is generated using npx next build) and their extensions are js so it raises an error when the .next files use require()

In Node, how do I elegantly handle requiring modules that read files in their directories?

For instance, in my project directory, I have:
|--bar.js
|--dir
|--foo.txt
|--readfile.js
readfile.js:
const fs = require('fs');
var foo = fs.readFileSync('foo.txt', 'utf8');
console.log(foo);
module.exports = {foo};
Running node readfile.js, everything works perfectly.
bar.js:
const readfile = require('./dir/readfile');
console.log(read.foo);
Running node bar.js, I get:
fs.js:663
return binding.open(pathModule.toNamespacedPath(path),
^
Error: ENOENT: no such file or directory, open 'foo.txt'
at Object.fs.openSync (fs.js:663:18)
at Object.fs.readFileSync (fs.js:568:33)
at Object.<anonymous> (/Users/fterh/Documents/Projects/playground/dir/readfile.js:3:14)
at Module._compile (module.js:660:30)
at Object.Module._extensions..js (module.js:671:10)
at Module.load (module.js:573:32)
at tryModuleLoad (module.js:513:12)
at Function.Module._load (module.js:505:3)
at Module.require (module.js:604:17)
at require (internal/module.js:11:18)
Fabians-MacBook-Pro:playground fterh$
I know it has to do with require('./dir/readfile') in bar.js, because Node then tries to search for "foo.txt" in the same directory as "bar.js". Currently, my fix is to use path.dirname(__filename) to get absolute paths, which would work regardless of whether I'm running the module directory or requiring it. I'm wondering if there is a more elegant way of doing things.
Use of require.resolve within readfile.js as follows:
const fs = require('fs');
let foo = fs.readFileSync(require.resolve('./foo.txt'), 'utf8');
console.log(foo);
module.exports = {foo};
Note: in the original question for bar.js it may have been intended to write: console.log(readfile.foo);.
require.resolve:
... return the resolved filename
Use __dirname to construct your path as that will always point to the directory where your module was loaded from, regardless of the current directory. This is one of the variables that is passed into a module so it has a unique value in the scope of each module and it's purpose is for exactly what you want (to do file operations relative to your module's directory).
const fs = require('fs');
const path = require('path');
var foo = fs.readFileSync(path.join(__dirname, 'foo.txt'), 'utf8');
console.log(foo);
module.exports = {foo};
Reference info for __dirname here.

'use-strict' enabled but not working in node

I have enabled use-strict mode in my .js file but when I run it, node keeps telling me that I don't have it enabled. PLEASE don't tell me to write "use-strict"; at the top of my file because I already tried that.
Here is my server.js file. I have been trying to see what is wrong but so far stack overflow has not been much help since most people seem to get this working on their first try.
require('use-strict')
'use-strict';
let util = require('util');
let http = require('http');
let Bot = require('#kikinteractive/kik');
var kik_username = process.env.KIK_USERNAME;
var kik_api_key = process.env.KIK_API_KEY;
var kik_baseUrl = process.env.KIK_BASEURL;
// Configure the bot API endpoint, details for your bot
let bot = new Bot({
username: kik_username,
apiKey: kik_api_key,
baseUrl: kik_baseUrl
});
bot.updateBotConfiguration();
bot.onTextMessage((message) => {
message.reply(message.body);
});
// Set up your server and start listening
let server = http.createServer(bot.incoming()).listen(8085);
Everything seems fine but when I run
$ node server.js
I keep getting this error
let util = require('util');
^^^
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:387:25)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:148:18)
at node.js:405:3
It tells me to enable strict mode BUT I ALREADY DID THAT. I even required an npm package to make sure I was doing it right! Can anyone make sense of what is happening?
No dash in 'use strict'
'use strict' // not 'use-strict'
Check out the documentation for further reference
You don't need to require an npm package. just put "use strict"; at the top of the js file.

Node's Commander can't prompt terminal

I'm using the popular Commander npm module in a command-line program i'm building. It works great except that all of the functions it provides that solicit user input -- aka, choose, prompt, and password -- fail to work.
As an example I'm using:
program
.command('test')
.action(function(param) {
program.prompt('Username: ', function(name){
console.log('hi %s', name);
});
program.prompt('Description:', function(desc){
console.log('description was "%s"', desc.trim());
});
}
);
This results in the following error (yet it is copy and pasted directly out of the documentation/examples):
TypeError: Object # has no method 'prompt'
at Command. (lib/tg.js:780:11)
at Command.listener (node_modules/commander/index.js:249:8)
at Command.emit (events.js:98:17)
at Command.parseArgs (/node_modules/commander/index.js:480:12)
at Command.parse (/node_modules/commander/index.js:372:21)
at Object. (/lib/tg.js:806:9)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
Try using the Node Prompt module. Install it from npm with this command:
npm install prompt --save
The docs can be found here: https://github.com/flatiron/prompt
Make sure you also require it in your code, usually at the top.
var prompt = require('prompt');
Remember, Node is non-blocking. Multiple prompts will attempt to get user input at the same time. To get around this, split your prompts up into functions and call the next prompt in the callback.
Example:
var first_prompt = function() {
var schema = {
// Read the docs on creating a prompt schema
};
prompt.start();
prompt.get(schema, function(err, result) {
// Do stuff with the input
// Call the next prompt
next_prompt();
});
};

Resources