NodeJS - standalone application to making user to input data - node.js

Does NodeJS has any functionality for accepting input via standard input from a user. In Browser based JS we used to use 'prompt' functionality for same but the this would not work on NodeJS standalone app.
node one.js
Enter any number:
<program accepts the number and does the processing>

As vinayr said, you should use readline. An example of what you desire:
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Input number:", function(numAnswer) {
// TODO: Log the answer in a database
var num = parseInt(numAnswer);
processingFunctionYouUse(num);
rl.close();
});

Use readline prompt http://nodejs.org/api/readline.html

I would like to suggest you to use stdio. It is a module that aims to simplify your life with standard input/output. One of its main features is the standard input reading, line by line, and it can be done as follows:
var stdio = require('stdio');
stdio.readByLines(function (line) {
// This function is called for every line while they are being read
}, function (err) {
// This function is called when the whole input has been processed
});
PD: I'm the stdio creator. :-)
(source: nodei.co)

Related

Custom Node JS REPL input/output stream

I need to have custom REPL input/output stream. for example I need to pass a piece of script to the REPL when some event happens and get it's output and do something with it.
To describe it more clear to you, I'm working on a vscode plugin (github: source code) which provides REPL. in my case I have a vscode WebView and from there, I get user input and then I want to pass that input to the node REPL and get its output and show it to user.
So, how would I achieve that? If you need more information please tell me. thanks in advance.
EDIT 1:
const replServer = repl.start({
input: /* what should be here? */,
output: /* what should be here? */
});
Edit 2:
can anyone explain me what is the usage of input/output parameters in the above example?
Here is a solution that worked for me.
const {
PassThrough
} = require('stream')
const repl = require('repl')
const input = new PassThrough()
const output = new PassThrough()
output.setEncoding('utf-8')
const _repl = repl.start({
prompt: 'awesomeRepl> ',
input,
output
})
_repl.on('exit', function() {
// Do something when REPL exit
console.log('Exited REPL...')
})
function evaluate(code) {
let evaluatedCode = ''
output.on('data', (chunk) => {
evaluatedCode += chunk.toString()
console.log(evaluatedCode)
})
input.write(`${code}\n`)
return result
}
evaluate('2 + 2') // should return 4
Notice created the REPL instance outside the evaluate function so we don't create a new instance for every call of evaluate
To create a repl server you just need to do
const repl = require('repl')
repl.start({prompt: "> ", input: input_stream, output: output_stream");
prompt is a string that is the prompt, stream is the input. input_stream needs to be a readable stream, output_stream needs to be a writable one. you can read more about streams here. Once the streams are working you can do
output_stream.on('data', (chunk) => {
14 //whatever you do with the data
15 });

NodeJs keystrokes get printed twice in console [duplicate]

This question already has answers here:
Get user input through Node.js console
(6 answers)
Closed last month.
I'm new to NodeJs and i'm used to C# were we can use
Console.ReadLine();
I looked into 'readline' and the node prompt package, but it either outputs all the user input twice while entering or, with the 'terminal: false' option, does not allow us to use the backspace.
var stdin = process.openStdin();
stdin.addListener("data", function(d) {
console.log("your input: " + d.toString());
});
This is like you take input value
There is a readline, you can use it like this:
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('How are you today? ', (answer) => {
// TODO: Log the answer in a database
console.log(`Thank you for your valuable feedback: ${answer}`);
rl.close();
});
Documentation is available here.

user input with node.js

I have the following Node.js code that behaves strangely:
#!/usr/bin/env node
"use strict";
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function input(prompt) {
rl.question(prompt, function (x) {
rl.close();
console.log("debug: " + x);
return x;
});
}
function main() {
var n = input("Number: ");
// console.log("value: " + n); // problematic line
}
main();
I want to mimic Python's raw_input, i.e. reading a line from the user. After showing the prompt, the program should be blocked until the user presses Enter.
If the "problematic line" is in comments, it works, the program is waiting for input. However, if this line is not in comments, then the program doesn't wait for input and n becomes undefined. Why? How to write a function that returns the user input?
That's because you are expecting the execution of input wait until return is called, which is not how this will work. The problematic line is indeed the previous one. First, input does not return anything, the return statement is the return of the question callback function, but then, you seem to misunderstand the execution flow, as we all have at some point (you'll get it pretty quick after some dead-ends like this one)
Your script is loaded
You declare and define rl, input and main
Main executes
You define n as the result of input
And here is where things start getting asynchronously funny
since question is asynchronous, its execution start but does not block the process
input returns undefined (while you're still waiting for the input)
you print that undefined
You write something on the input
question() finishes its execution and calls the callback (the function you gave as second parameter)
rl is closed
the callback function returns the line, and it is swallowed by the void (this is not technical terminology, just a metaphor)
You may want to do it like this:
#!/usr/bin/env node
"use strict";
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function input(prompt, callback) {
rl.question(prompt, function (x) {
rl.close();
callback(x);
});
}
function main() {
var n = input("Number: ", console.log);
}
main();
If you're new to javascript and node, you may find very useful to use learnyounode and the node code school path or even, if you have the time, the money and the opportunity, read Node.js, MongoDB, and AngularJS Web Development, by Brad Dayley.

Is there a way to get synchronous terminal input in Node.js

I have looked at similar questions on SO and I have an ongoing question about if it is possible to get synchronous input from the command line.
I know about readline and process.stdin.on('readable', ...) but both of those seem to be asynchronous.
I am looking to for a way to prompt the user for input where code later on in my script does not run before there is user input.
May be you can try this in case if you know fix number of inputs you want in sync manner.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let i = 0;
rl.question('Number of inputs : ', (answer1) => {
rl.on('line', (answer2) => {
console.log(`input: ${answer2}`);
i++;
if (i >= answer1) {
rl.close();
}
});
});

Parse output of spawned node.js child process line by line

I have a PhantomJS/CasperJS script which I'm running from within a node.js script using process.spawn(). Since CasperJS doesn't support require()ing modules, I'm trying to print commands from CasperJS to stdout and then read them in from my node.js script using spawn.stdout.on('data', function(data) {}); in order to do things like add objects to redis/mongoose (convoluted, yes, but seems more straightforward than setting up a web service for this...) The CasperJS script executes a series of commands and creates, say, 20 screenshots which need to be added to my database.
However, I can't figure out how to break the data variable (a Buffer?) into lines... I've tried converting it to a string and then doing a replace, I've tried doing spawn.stdout.setEncoding('utf8'); but nothing seems to work...
Here is what I have right now
var spawn = require('child_process').spawn;
var bin = "casperjs"
//googlelinks.js is the example given at http://casperjs.org/#quickstart
var args = ['scripts/googlelinks.js'];
var cspr = spawn(bin, args);
//cspr.stdout.setEncoding('utf8');
cspr.stdout.on('data', function (data) {
var buff = new Buffer(data);
console.log("foo: " + buff.toString('utf8'));
});
cspr.stderr.on('data', function (data) {
data += '';
console.log(data.replace("\n", "\nstderr: "));
});
cspr.on('exit', function (code) {
console.log('child process exited with code ' + code);
process.exit(code);
});
https://gist.github.com/2131204
Try this:
cspr.stdout.setEncoding('utf8');
cspr.stdout.on('data', function(data) {
var str = data.toString(), lines = str.split(/(\r?\n)/g);
for (var i=0; i<lines.length; i++) {
// Process the line, noting it might be incomplete.
}
});
Note that the "data" event might not necessarily break evenly between lines of output, so a single line might span multiple data events.
I've actually written a Node library for exactly this purpose, it's called stream-splitter and you can find it on Github: samcday/stream-splitter.
The library provides a special Stream you can pipe your casper stdout into, along with a delimiter (in your case, \n), and it will emit neat token events, one for each line it has split out from the input Stream. The internal implementation for this is very simple, and delegates most of the magic to substack/node-buffers which means there's no unnecessary Buffer allocations/copies.
I found a nicer way to do this with just pure node, which seems to work well:
const childProcess = require('child_process');
const readline = require('readline');
const cspr = childProcess.spawn(bin, args);
const rl = readline.createInterface({ input: cspr.stdout });
rl.on('line', line => /* handle line here */)
Adding to maerics' answer, which does not deal properly with cases where only part of a line is fed in a data dump (theirs will give you the first part and the second part of the line individually, as two separate lines.)
var _breakOffFirstLine = /\r?\n/
function filterStdoutDataDumpsToTextLines(callback){ //returns a function that takes chunks of stdin data, aggregates it, and passes lines one by one through to callback, all as soon as it gets them.
var acc = ''
return function(data){
var splitted = data.toString().split(_breakOffFirstLine)
var inTactLines = splitted.slice(0, splitted.length-1)
var inTactLines[0] = acc+inTactLines[0] //if there was a partial, unended line in the previous dump, it is completed by the first section.
acc = splitted[splitted.length-1] //if there is a partial, unended line in this dump, store it to be completed by the next (we assume there will be a terminating newline at some point. This is, generally, a safe assumption.)
for(var i=0; i<inTactLines.length; ++i){
callback(inTactLines[i])
}
}
}
usage:
process.stdout.on('data', filterStdoutDataDumpsToTextLines(function(line){
//each time this inner function is called, you will be getting a single, complete line of the stdout ^^
}) )
You can give this a try. It will ignore any empty lines or empty new line breaks.
cspr.stdout.on('data', (data) => {
data = data.toString().split(/(\r?\n)/g);
data.forEach((item, index) => {
if (data[index] !== '\n' && data[index] !== '') {
console.log(data[index]);
}
});
});
Old stuff but still useful...
I have made a custom stream Transform subclass for this purpose.
See https://stackoverflow.com/a/59400367/4861714
#nyctef's answer uses an official nodejs package.
Here is a link to the documentation: https://nodejs.org/api/readline.html
The node:readline module provides an interface for reading data from a Readable stream (such as process.stdin) one line at a time.
My personal use-case is parsing json output from the "docker watch" command created in a spawned child_process.
const dockerWatchProcess = spawn(...)
...
const rl = readline.createInterface({
input: dockerWatchProcess.stdout,
output: null,
});
rl.on('line', (log: string) => {
console.log('dockerWatchProcess event::', log);
// code to process a change to a docker event
...
});

Resources