Add UnhandledStreamPipee Quality query and tests to detect missing error handlers in Node.js streams

This commit is contained in:
Napalys Klicius
2025-05-20 12:45:11 +02:00
parent d1e769ba54
commit c27157f021
4 changed files with 246 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
| test.js:4:5:4:28 | stream. ... nation) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:19:5:19:17 | s2.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:45:5:45:30 | stream2 ... ation2) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:60:5:60:30 | stream2 ... ation2) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:66:5:66:21 | stream.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:79:5:79:25 | s2.pipe ... ation2) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:94:5:94:21 | stream.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:109:26:109:37 | s.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:116:5:116:21 | stream.pipe(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |
| test.js:125:5:125:26 | getStre ... e(dest) | Stream pipe without error handling on the source stream. Errors won't propagate downstream and may be silently dropped. |

View File

@@ -0,0 +1,137 @@
function test() {
{
const stream = getStream();
stream.pipe(destination); // $Alert
}
{
const stream = getStream();
stream.pipe(destination);
stream.on('error', handleError);
}
{
const stream = getStream();
stream.on('error', handleError);
stream.pipe(destination);
}
{
const stream = getStream();
const s2 = stream;
s2.pipe(dest); // $Alert
}
{
const stream = getStream();
stream.on('error', handleError);
const s2 = stream;
s2.pipe(dest);
}
{
const stream = getStream();
const s2 = stream;
s2.on('error', handleError);
s2.pipe(dest);
}
{
const s = getStream().on('error', handler);
const d = getDest();
s.pipe(d);
}
{
getStream().on('error', handler).pipe(dest);
}
{
const stream = getStream();
stream.on('error', handleError);
const stream2 = stream.pipe(destination);
stream2.pipe(destination2); // $Alert
}
{
const stream = getStream();
stream.on('error', handleError);
const destination = getDest();
destination.on('error', handleError);
const stream2 = stream.pipe(destination);
const s3 = stream2;
s = s3.pipe(destination2);
}
{
const stream = getStream();
stream.on('error', handleError);
const stream2 = stream.pipe(destination);
stream2.pipe(destination2); // $Alert
}
{ // Error handler on destination instead of source
const stream = getStream();
const dest = getDest();
dest.on('error', handler);
stream.pipe(dest); // $Alert
}
{ // Multiple aliases, error handler on one
const stream = getStream();
const alias1 = stream;
const alias2 = alias1;
alias2.on('error', handleError);
alias1.pipe(dest);
}
{ // Multiple pipes, handler after first pipe
const stream = getStream();
const s2 = stream.pipe(destination1);
stream.on('error', handleError);
s2.pipe(destination2); // $Alert
}
{ // Handler registered via .once
const stream = getStream();
stream.once('error', handleError);
stream.pipe(dest);
}
{ // Handler registered with arrow function
const stream = getStream();
stream.on('error', (err) => handleError(err));
stream.pipe(dest);
}
{ // Handler registered for unrelated event
const stream = getStream();
stream.on('close', handleClose);
stream.pipe(dest); // $Alert
}
{ // Error handler registered after pipe, but before error
const stream = getStream();
stream.pipe(dest);
setTimeout(() => stream.on('error', handleError), 8000); // $MISSING:Alert
}
{ // Pipe in a function, error handler outside
const stream = getStream();
function doPipe(s) { s.pipe(dest); }
stream.on('error', handleError);
doPipe(stream);
}
{ // Pipe in a function, error handler not set
const stream = getStream();
function doPipe(s) { s.pipe(dest); } // $Alert
doPipe(stream);
}
{ // Dynamic event assignment
const stream = getStream();
const event = 'error';
stream.on(event, handleError);
stream.pipe(dest); // $SPURIOUS:Alert
}
{ // Handler assigned via variable property
const stream = getStream();
const handler = handleError;
stream.on('error', handler);
stream.pipe(dest);
}
{ // Pipe with no intermediate variable, no error handler
getStream().pipe(dest); // $Alert
}
{ // Handler set via .addListener synonym
const stream = getStream();
stream.addListener('error', handleError);
stream.pipe(dest);
}
{ // Handler set via .once after .pipe
const stream = getStream();
stream.pipe(dest);
stream.once('error', handleError);
}
}

View File

@@ -0,0 +1,2 @@
query: Quality/UnhandledStreamPipe.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql