Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

readline/promises handle batch line inputs incorrectly #56608

Open
nick-loginov opened this issue Jan 15, 2025 · 0 comments
Open

readline/promises handle batch line inputs incorrectly #56608

nick-loginov opened this issue Jan 15, 2025 · 0 comments

Comments

@nick-loginov
Copy link

nick-loginov commented Jan 15, 2025

Version

v20.17.0

Platform

Linux 5.15.167.4-microsoft-standard-WSL2 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

Start with the following code:

// script.js
const readline = require("readline/promises");
const { stdin: input, stdout: output } = require("node:process");
const rl = readline.createInterface({ input, output });

(async() => {
    const input1 = await rl.question("Enter input1:");
    const input2 = await rl.question("Enter input2:");
    console.log("input1:", input1);
    console.log("input2:", input2);
})();

Now try feeding data with multiple lines as one batch to stdin:

echo -e "line 1\nline 2\n" | node script.js

How often does it reproduce? Is there a required condition?

No, it appears each time you try to process multiple lines of input at once using promise version of readline.

What is the expected behavior? Why is that the expected behavior?

What you get is not what you expect, all lines of input land to first variable which is input1, instead of assigning correspondingly to input1 and input2. This is due to first rl.question consuming all event data of the stdin. One way of solving this is queueing the inputs in one place, so that results would be correctly resolved to all rl.question calls, see prototype proposition bellow.

What do you see instead?

This is just a scratch, showing that problem exists, not the best approach right here:

// script.js
const readline = require("readline");
const { stdin: input, stdout: output } = require("node:process");
const rl = readline.createInterface({ input, output });

const lines = [];
let readLineTask;

rl.on("line", (line) => {
  if (readLineTask) {
    readLineTask(line);
    readLineTask = undefined;
  } else {
    lines.push(line);
  }
});

async function question(message) {
  output.write(message);
  if (lines.length > 0) {
    return lines.shift();
  } else {
    return new Promise((resolve, reject) => {
      readLineTask = resolve;
    });
  }
}
(async() => {
    const input1 = await question("Enter input1:\n");
    const input2 = await question("Enter input2:\n");
    console.log("input1:", input1);
    console.log("input2:", input2);
})();

The better solution would be feeding stdout stream line by line to corresponding questions, so that the order of input and output would not be violated, in case above the order is following:

Enter input1:
1
2

Enter input2:
input1: 1
input2: 2

First input being read, and only then second question comes up, the right output should be:

Enter input1:
1

Enter input2:
2

input1: 1
input2: 2

Additional information

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant