From 74716d35f93bd8bbb3bc2217811d29bede012f0f Mon Sep 17 00:00:00 2001 From: koreahghg Date: Wed, 21 Oct 2026 16:21:16 +0900 Subject: [PATCH] stream: truncate fractional limits in take() and drop() toIntegerOrInfinity() coerced the limit with Number() but never truncated it, so a fractional limit such as 1.5 made take() yield one chunk too many and drop() skip one chunk too many. A negative fraction in (-1, 0) also threw ERR_OUT_OF_RANGE, although ToIntegerOrInfinity() maps it to -0, which is a valid limit. Truncate the value toward zero before the range check so the results match Iterator.prototype.take() and Iterator.prototype.drop(). Signed-off-by: koreahghg Assisted-by: Claude Code --- lib/internal/streams/operators.js | 6 ++++-- test/parallel/test-stream-drop-take.js | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/internal/streams/operators.js b/lib/internal/streams/operators.js index a5cbe1af428f..1b164d013de5 100644 --- a/lib/internal/streams/operators.js +++ b/lib/internal/streams/operators.js @@ -4,6 +4,7 @@ const { ArrayPrototypePush, Boolean, MathFloor, + MathTrunc, Number, NumberIsNaN, Promise, @@ -314,10 +315,11 @@ function toIntegerOrInfinity(number) { if (NumberIsNaN(number)) { return 0; } - if (number < 0) { + const integer = MathTrunc(number); + if (integer < 0) { throw new ERR_OUT_OF_RANGE('number', '>= 0', number); } - return number; + return integer; } function drop(number, options = undefined) { diff --git a/test/parallel/test-stream-drop-take.js b/test/parallel/test-stream-drop-take.js index da09d242f0c4..1a49bb255f15 100644 --- a/test/parallel/test-stream-drop-take.js +++ b/test/parallel/test-stream-drop-take.js @@ -81,6 +81,18 @@ const naturals = () => from(async function*() { })().then(common.mustCall()); } +{ + // Fractional limits are truncated toward zero + (async () => { + assert.deepStrictEqual(await from([1, 2, 3, 4]).take(1.5).toArray(), [1]); + assert.deepStrictEqual(await from([1, 2, 3, 4]).drop(1.5).toArray(), [2, 3, 4]); + assert.deepStrictEqual(await from([1, 2, 3, 4]).take(0.5).toArray(), []); + assert.deepStrictEqual(await from([1, 2, 3, 4]).drop(0.5).toArray(), [1, 2, 3, 4]); + assert.deepStrictEqual(await from([1, 2]).take(-0.5).toArray(), []); + assert.deepStrictEqual(await from([1, 2]).drop(-0.5).toArray(), [1, 2]); + })().then(common.mustCall()); +} + { // Support for AbortSignal const ac = new AbortController(); @@ -108,6 +120,7 @@ const naturals = () => from(async function*() { // Error cases const invalidArgs = [ -1, + -1.5, -Infinity, -40, ];