Skip to content

Commit 4c8e8e5

Browse files
authored
Update to Node.js 18.19.0, add Node 21.x to CI (#528)
* Update to Node.js 18.19.0, add Node 21.x to CI Signed-off-by: Matteo Collina <[email protected]> * Add polyfill for addAbortListener Signed-off-by: Matteo Collina <[email protected]> * Running on Node 16 Signed-off-by: Matteo Collina <[email protected]> * fixup old nodes Signed-off-by: Matteo Collina <[email protected]> * fixup Signed-off-by: Matteo Collina <[email protected]> * fixup Signed-off-by: Matteo Collina <[email protected]> * fixup Signed-off-by: Matteo Collina <[email protected]> * Add validators to addAbortListener and AbortSignalAny Signed-off-by: Matteo Collina <[email protected]> --------- Signed-off-by: Matteo Collina <[email protected]>
1 parent 268229d commit 4c8e8e5

39 files changed

+1256
-611
lines changed

.github/workflows/node.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
os: [ubuntu-latest, windows-latest, macos-latest]
16-
node-version: [12.x, 14.x, 16.x, 18.x, 20.x]
16+
node-version: [12.x, 14.x, 16.x, 18.x, 20.x, 21.x]
1717
exclude:
1818
- os: windows-latest
1919
node-version: 12.x

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
npm install readable-stream
1212
```
1313

14-
This package is a mirror of the streams implementations in Node.js 18.16.0.
14+
This package is a mirror of the streams implementations in Node.js 18.19.0.
1515

16-
Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v18.16.0/docs/api/stream.html).
16+
Full documentation may be found on the [Node.js website](https://nodejs.org/dist/v18.19.0/docs/api/stream.html).
1717

1818
If you want to guarantee a stable streams base, regardless of what version of
1919
Node you, or the users of your libraries are using, use **readable-stream** _only_ and avoid the _"stream"_ module in Node-core, for background see [this blogpost](http://r.va.gg/2014/06/why-i-dont-use-nodes-core-stream-module.html).

build/build.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ async function extract(nodeVersion, tarFile) {
6969
})
7070

7171
await finished(tarFile.pipe(parser))
72+
info('extraction done')
7273
return contents
7374
}
7475

build/replacements.mjs

+74-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ const internalStreamsBufferPolyfill = [
99
`
1010
]
1111

12+
const noNodeColon = ["node:", '']
13+
1214
const internalStreamsAbortControllerPolyfill = [
1315
"'use strict'",
1416
`
@@ -42,6 +44,11 @@ const internalStreamsNoRequireAbortController = [
4244
'const AbortController = globalThis.AbortController || require(\'abort-controller\').AbortController;'
4345
]
4446

47+
const internalStreamsNoRequireAbortController2 = [
48+
'const \\{ AbortController, AbortSignal \\} = .+',
49+
'const AbortController = globalThis.AbortController || require(\'abort-controller\').AbortController;'
50+
]
51+
4552
const internalStreamsRequireInternal = ["require\\('internal/([^']+)'\\)", "require('../$1')"]
4653

4754
const internalStreamsRequireErrors = ["require\\('internal/errors'\\)", "require('../../ours/errors')"]
@@ -74,7 +81,12 @@ const internalStreamsRequireWebStream = ["require\\('internal/webstreams/adapter
7481

7582
const internalStreamsWeakHandler = [
7683
"const \\{ kWeakHandler \\} = require\\('../event_target'\\);",
77-
"const kWeakHandler = require('../../ours/primordials').Symbol('kWeak');"
84+
"require\\('../event_target'\\);const kWeakHandler = require('../../ours/primordials').Symbol('kWeak');"
85+
]
86+
87+
const internalStreamsWeakHandler2 = [
88+
"const \\{ kWeakHandler, kResistStopPropagation \\} = .*;",
89+
"const kWeakHandler = require('../../ours/primordials').Symbol('kWeak');\nconst kResistStopPropagation = require('../../ours/primordials').Symbol('kResistStopPropagation');"
7890
]
7991

8092
const internalValidatorsNoCoalesceAssignment = [
@@ -142,6 +154,7 @@ const testCommonKnownGlobals = [
142154
typeof AbortController !== 'undefined' ? AbortController : require('abort-controller').AbortController,
143155
typeof AbortSignal !== 'undefined' ? AbortSignal : require('abort-controller').AbortSignal,
144156
typeof EventTarget !== 'undefined' ? EventTarget : require('event-target-shim').EventTarget,
157+
typeof navigator !== 'undefined' ? navigator : {},
145158
`
146159
]
147160

@@ -238,6 +251,47 @@ const readmeLink = ['(\\[Node.js website\\]\\(https://nodejs.org/dist/v)(\\d+.\\
238251

239252
const streamRequire = [ "require\\('stream'\\)", "require('../../lib/stream.js')" ]
240253

254+
const removeWebStreamsFromDuplexFromTest= [
255+
'const { ReadableStream, WritableStream } = .+;',
256+
`function makeATestReadableStream(value) {
257+
return Readable.from([value])
258+
}
259+
function makeATestWritableStream(writeFunc) {
260+
return new Writable({
261+
write(chunk, enc, cb) {
262+
writeFunc(chunk)
263+
cb()
264+
}
265+
})
266+
}
267+
`
268+
]
269+
270+
const duplexFromTestWebStreamNeutralizeReadable = [
271+
'makeATestReadableStream\\(value\\) {',
272+
'makeATestReadableStreamOff(value) {'
273+
]
274+
275+
const duplexFromTestWebStreamNeutralizeWritable = [
276+
'makeATestWritableStream\\(writeFunc\\) {',
277+
'makeATestWritableStreamOff(writeFunc) {'
278+
]
279+
280+
const polyfillAddAbortListener = [
281+
'addAbortListener \\?\\?= require\\(\'events\'\\)\\.addAbortListener',
282+
'addAbortListener = addAbortListener || require(\'../../ours/util\').addAbortListener'
283+
]
284+
285+
const abortSignalAny = [
286+
'AbortSignal.any',
287+
'require(\'../../ours/util\').AbortSignalAny'
288+
]
289+
290+
const asyncDisposeTest = [
291+
'Symbol.asyncDispose',
292+
'require(\'../../lib/ours/primordials\').SymbolAsyncDispose'
293+
]
294+
241295
export const replacements = {
242296
'lib/_stream.+': [legacyStreamsRequireStream],
243297
'lib/internal/streams/duplexify.+': [
@@ -248,7 +302,13 @@ export const replacements = {
248302
],
249303
'lib/internal/streams/(operators|pipeline).+': [
250304
internalStreamsAbortControllerPolyfill,
251-
internalStreamsNoRequireAbortController
305+
internalStreamsNoRequireAbortController,
306+
internalStreamsNoRequireAbortController2,
307+
internalStreamsWeakHandler2,
308+
abortSignalAny
309+
],
310+
'lib/internal/streams/add-abort-signal.js': [
311+
polyfillAddAbortListener
252312
],
253313
'lib/internal/streams/readable.js': [
254314
removefromWebReadableMethod,
@@ -267,7 +327,8 @@ export const replacements = {
267327
internalStreamsRequireWebStream,
268328
internalStreamsRequireInternal,
269329
internalStreamsWeakHandler,
270-
internalStreamsInspectCustom
330+
internalStreamsInspectCustom,
331+
polyfillAddAbortListener
271332
],
272333
'lib/internal/validators.js': [
273334
internalValidatorsRequireAssert,
@@ -305,10 +366,18 @@ export const replacements = {
305366
testParallelBindings,
306367
testParallelHasOwn,
307368
testParallelSilentConsole,
308-
testParallelTimersPromises
369+
testParallelTimersPromises,
370+
noNodeColon
371+
],
372+
'test/parallel/test-stream-duplex-from.js': [
373+
testParallelDuplexFromBlob,
374+
testParallelDuplexSkipWithoutBlob,
375+
duplexFromTestWebStreamNeutralizeReadable,
376+
duplexFromTestWebStreamNeutralizeWritable,
377+
removeWebStreamsFromDuplexFromTest
309378
],
310-
'test/parallel/test-stream-duplex-from.js': [testParallelDuplexFromBlob, testParallelDuplexSkipWithoutBlob],
311379
'test/parallel/test-stream-finished.js': [testParallelFinishedEvent],
380+
'test/parallel/test-stream-readable-dispose.js': [asyncDisposeTest],
312381
'test/parallel/test-stream-flatMap.js': [testParallelFlatMapWinLineSeparator],
313382
'test/parallel/test-stream-preprocess.js': [testParallelPreprocessWinLineSeparator],
314383
'test/parallel/test-stream-writable-samecb-singletick.js': [

lib/internal/streams/add-abort-signal.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
'use strict'
22

3+
const { SymbolDispose } = require('../../ours/primordials')
34
const { AbortError, codes } = require('../../ours/errors')
45
const { isNodeStream, isWebStream, kControllerErrorFunction } = require('./utils')
56
const eos = require('./end-of-stream')
67
const { ERR_INVALID_ARG_TYPE } = codes
8+
let addAbortListener
79

810
// This method is inlined here for readable-stream
911
// It also does not allow for signal to not exist on the stream
@@ -42,8 +44,9 @@ module.exports.addAbortSignalNoValidate = function (signal, stream) {
4244
if (signal.aborted) {
4345
onAbort()
4446
} else {
45-
signal.addEventListener('abort', onAbort)
46-
eos(stream, () => signal.removeEventListener('abort', onAbort))
47+
addAbortListener = addAbortListener || require('../../ours/util').addAbortListener
48+
const disposable = addAbortListener(signal, onAbort)
49+
eos(stream, disposable[SymbolDispose])
4750
}
4851
return stream
4952
}

lib/internal/streams/compose.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module.exports = function compose(...streams) {
7474
d = new Duplex({
7575
// TODO (ronag): highWaterMark?
7676
writableObjectMode: !!(head !== null && head !== undefined && head.writableObjectMode),
77-
readableObjectMode: !!(tail !== null && tail !== undefined && tail.writableObjectMode),
77+
readableObjectMode: !!(tail !== null && tail !== undefined && tail.readableObjectMode),
7878
writable,
7979
readable
8080
})

lib/internal/streams/destroy.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const {
1212
AbortError
1313
} = require('../../ours/errors')
1414
const { Symbol } = require('../../ours/primordials')
15-
const { kDestroyed, isDestroyed, isFinished, isServerRequest } = require('./utils')
15+
const { kIsDestroyed, isDestroyed, isFinished, isServerRequest } = require('./utils')
1616
const kDestroy = Symbol('kDestroy')
1717
const kConstruct = Symbol('kConstruct')
1818
function checkError(err, w, r) {
@@ -278,7 +278,7 @@ function destroyer(stream, err) {
278278
process.nextTick(emitCloseLegacy, stream)
279279
}
280280
if (!stream.destroyed) {
281-
stream[kDestroyed] = true
281+
stream[kIsDestroyed] = true
282282
}
283283
}
284284
module.exports = {

lib/internal/streams/duplexify.js

+20-21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ const {
1313
isNodeStream,
1414
isReadableNodeStream,
1515
isWritableNodeStream,
16-
isDuplexNodeStream
16+
isDuplexNodeStream,
17+
isReadableStream,
18+
isWritableStream
1719
} = require('./utils')
1820
const eos = require('./end-of-stream')
1921
const {
@@ -23,6 +25,7 @@ const {
2325
const { destroyer } = require('./destroy')
2426
const Duplex = require('./duplex')
2527
const Readable = require('./readable')
28+
const Writable = require('./writable')
2629
const { createDeferredPromise } = require('../../ours/util')
2730
const from = require('./from')
2831
const Blob = globalThis.Blob || bufferModule.Blob
@@ -77,17 +80,16 @@ module.exports = function duplexify(body, name) {
7780
readable: false
7881
})
7982
}
80-
81-
// TODO: Webstreams
82-
// if (isReadableStream(body)) {
83-
// return _duplexify({ readable: Readable.fromWeb(body) });
84-
// }
85-
86-
// TODO: Webstreams
87-
// if (isWritableStream(body)) {
88-
// return _duplexify({ writable: Writable.fromWeb(body) });
89-
// }
90-
83+
if (isReadableStream(body)) {
84+
return _duplexify({
85+
readable: Readable.fromWeb(body)
86+
})
87+
}
88+
if (isWritableStream(body)) {
89+
return _duplexify({
90+
writable: Writable.fromWeb(body)
91+
})
92+
}
9193
if (typeof body === 'function') {
9294
const { value, write, final, destroy } = fromAsyncGen(body)
9395
if (isIterable(value)) {
@@ -144,15 +146,12 @@ module.exports = function duplexify(body, name) {
144146
writable: false
145147
})
146148
}
147-
148-
// TODO: Webstreams.
149-
// if (
150-
// isReadableStream(body?.readable) &&
151-
// isWritableStream(body?.writable)
152-
// ) {
153-
// return Duplexify.fromWeb(body);
154-
// }
155-
149+
if (
150+
isReadableStream(body === null || body === undefined ? undefined : body.readable) &&
151+
isWritableStream(body === null || body === undefined ? undefined : body.writable)
152+
) {
153+
return Duplexify.fromWeb(body)
154+
}
156155
if (
157156
typeof (body === null || body === undefined ? undefined : body.writable) === 'object' ||
158157
typeof (body === null || body === undefined ? undefined : body.readable) === 'object'

lib/internal/streams/end-of-stream.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const { AbortError, codes } = require('../../ours/errors')
1111
const { ERR_INVALID_ARG_TYPE, ERR_STREAM_PREMATURE_CLOSE } = codes
1212
const { kEmptyObject, once } = require('../../ours/util')
1313
const { validateAbortSignal, validateFunction, validateObject, validateBoolean } = require('../validators')
14-
const { Promise, PromisePrototypeThen } = require('../../ours/primordials')
14+
const { Promise, PromisePrototypeThen, SymbolDispose } = require('../../ours/primordials')
1515
const {
1616
isClosed,
1717
isReadable,
@@ -28,6 +28,7 @@ const {
2828
willEmitClose: _willEmitClose,
2929
kIsClosedPromise
3030
} = require('./utils')
31+
let addAbortListener
3132
function isRequest(stream) {
3233
return stream.setHeader && typeof stream.abort === 'function'
3334
}
@@ -212,12 +213,13 @@ function eos(stream, options, callback) {
212213
if (options.signal.aborted) {
213214
process.nextTick(abort)
214215
} else {
216+
addAbortListener = addAbortListener || require('../../ours/util').addAbortListener
217+
const disposable = addAbortListener(options.signal, abort)
215218
const originalCallback = callback
216219
callback = once((...args) => {
217-
options.signal.removeEventListener('abort', abort)
220+
disposable[SymbolDispose]()
218221
originalCallback.apply(stream, args)
219222
})
220-
options.signal.addEventListener('abort', abort)
221223
}
222224
}
223225
return cleanup
@@ -238,12 +240,13 @@ function eosWeb(stream, options, callback) {
238240
if (options.signal.aborted) {
239241
process.nextTick(abort)
240242
} else {
243+
addAbortListener = addAbortListener || require('../../ours/util').addAbortListener
244+
const disposable = addAbortListener(options.signal, abort)
241245
const originalCallback = callback
242246
callback = once((...args) => {
243-
options.signal.removeEventListener('abort', abort)
247+
disposable[SymbolDispose]()
244248
originalCallback.apply(stream, args)
245249
})
246-
options.signal.addEventListener('abort', abort)
247250
}
248251
}
249252
const resolverFn = (...args) => {

0 commit comments

Comments
 (0)