In nodejs, I am creating a CLI using readline module. initially I using the following code to start the prompt
let _interface = require('readline').createInterface{
input: process.stdin,
output: process.stdout,
prompt: '>'};
_interface.prompt();
/*some operation*/
_interface.prompt();
But I am trying to change the prompt icon from > to $ as the user try's to change it. How can this be done, without restarting the prompt.
You can achieve this by using rl.setPrompt() method.
Consider this example
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: '> '
});
rl.prompt();
rl.on('line', (line) => {
if(line.trim()=='change --$'){
rl.setPrompt('$');
}
rl.prompt();
}).on('close', () => {
console.log('Have a great day!');
process.exit(0);
});
I hope it will work for you.
Related
I'm currently working on a method for a simple console game. And I want to test this method through jest mocking. But I'm having a hard time. Any help would be appreciated.
index.js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
class App {
play() {
rl.question("Input Numbers ", (userInput) => {
const userNumbers = userInput.split("").map(Number);
if (userNumbers.length !== 3) {
throw new Error("[ERROR] You have to input 3 numbers");
return;
}
});
}
}
module.exports = App;
I tried in index.test.js with jest
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const App = require("../src/App");
test("throws an error if user input 4 numbers", () => {
const mockQuestion = jest.fn().mockImplementation((question, callback) => {
callback("1234");
});
rl.question = mockQuestion;
const app = new App();
expect(() => {
app.play();
}).toThrow("[ERROR] You have to input 3 numbers");
});
But I got this fail message
Expected substring: "[ERROR] You have to input 3 numbers"
Received function did not throw
enter image description here
I am trying to keep adding numbers in a loop as shown in the code below:
const readline = require('readline');
const askOnCommandLine = (question) =>
new Promise((resolve) => {
const p = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: question,
});
p.on('line', (input) => {
resolve(input);
});
p.prompt();
});
let counter = 0;
(async () => {
while (true) {
console.log('Loop:', counter);
const number1 = await askOnCommandLine('Enter 1st number: ');
const number2 = await askOnCommandLine('Enter 2nd number: ');
console.log('Addition:', parseInt(number1) + parseInt(number2));
counter += 1;
}
})();
But there are two problems here:
It prints a single key press multiple times as shown in the screenshot.
After a few loops, there an error as follows:
Enter 2nd number:
(node:706492) MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 end listeners added to [ReadStream]. Use emitter.setMaxListeners() to increase limit
(Use `node --trace-warnings ...` to show where the warning was created)
Just like event listeners in the browser, you need to be dealing with these stream interfaces after you're done with them, otherwise they'll just keep building up in memory (hence the warning and the unexpected behavior). It looks like readline exposes a close() method, why not close the stream when you're done with it?
const askOnCommandLine = (question) =>
new Promise((resolve) => {
const p = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: question,
});
p.on('line', (input) => {
resolve(input);
p.close();
});
p.prompt();
});
Node.js readline property doesn't stop for input, instead continues program, causing app to crash. While trying to solve this I found out that apparently node does the whole code simultaneously and doesn't because of that stop for input. I found out ways to run this code but they didn't work for me.
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var token;
var pass;
rl.question('token: ', (tok) => {
token = tok;
rl.close();
});
rl.question('pass: ', (pas) => {
pass = pas;
rl.close();
});
What can I do to solve this?
I hope you are looking something like below:
const readLine = require('readline');
const util = require('util')
const { promisify } = util;
const readline = readLine.createInterface({
input: process.stdin,
output: process.stdout,
});
// Prepare readline.question for promisification
readline.question[util.promisify.custom] = (question) => {
return new Promise((resolve) => {
readline.question(question, resolve);
});
};
let questionPs = promisify(readline.question);
async function askQuestions (questions,readline) {
let answers= [];
for(let i=0;i<2;i++){
let tmp = await questionPs(q[i]);
answers.push(tmp)
}
console.log(answers);
readline.close();
}
// Usage example:
let q = ['token:','pass:']
askQuestions(q,readline)
When I press and hold ENTER on my keyboard, the readline module will then output empty lines to my writeable stream(in this case it is process.stdout).
But since I don't want empty lines to clutter my console I want to prevent it somehow from being outputted.
Can I use something to filter out empty lines in my stream? Maybe using a transform stream of some sorts?
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
removeHistoryDuplicates: true
});
rl.on("line", (line) => {
if(line.trim().length === 0) {
// don't output anything, but it is already too late because it is already written to stream :'-(
}
rl.prompt();
})
use this
readline.cursorTo(process.stdout, 0,0);
enter will automatically be ignored and return to the begining
https://nodejs.org/api/readline.html#readline_readline_clearline_stream_dir
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
removeHistoryDuplicates: true
});
const enterPressed=(line)=>{
return line.replace(/[^a-zA-Z]/g, "").trim().length === 0
}
rl.on("line", (line) => {
if(enterPressed(line)) {
readline.cursorTo(process.stdout, 0,0);
}
rl.prompt();
})
I need to take input from the user such as the listening and connecting port, I've tried seperating the rl.on('line')'s and I've tried using them inside one another. If the is some way to save the data from the line to a global variabel that would work too, but I don't know how.
const readline = require('readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.on('line', (line) => {
const listenPort = line
rl.on('line', (line) => {
const connectPort = line
})
})