diff --git a/lib/internal/abort_controller.js b/lib/internal/abort_controller.js index 5bd94585cc92a4..3233fb8c0c2ee2 100644 --- a/lib/internal/abort_controller.js +++ b/lib/internal/abort_controller.js @@ -25,6 +25,7 @@ const { } = require('internal/event_target'); const { customInspectSymbol, + kEnumerableProperty, } = require('internal/util'); const { inspect } = require('internal/util/inspect'); const { @@ -253,7 +254,7 @@ function ClonedAbortSignal() { ClonedAbortSignal.prototype[kDeserialize] = () => {}; ObjectDefineProperties(AbortSignal.prototype, { - aborted: { enumerable: true } + aborted: kEnumerableProperty, }); ObjectDefineProperty(AbortSignal.prototype, SymbolToStringTag, { @@ -322,8 +323,8 @@ class AbortController { } ObjectDefineProperties(AbortController.prototype, { - signal: { enumerable: true }, - abort: { enumerable: true } + signal: kEnumerableProperty, + abort: kEnumerableProperty, }); ObjectDefineProperty(AbortController.prototype, SymbolToStringTag, { diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index 72499d27ab854a..c022bb44223b5b 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -5,7 +5,6 @@ const { JSONParse, JSONStringify, ObjectDefineProperties, - ObjectGetOwnPropertyDescriptor, SafeSet, SymbolToStringTag, StringPrototypeRepeat, @@ -60,6 +59,7 @@ const { } = require('internal/crypto/util'); const { + kEnumerableProperty, lazyDOMException, } = require('internal/util'); @@ -703,10 +703,7 @@ ObjectDefineProperties( writable: false, value: 'Crypto', }, - subtle: { - ...ObjectGetOwnPropertyDescriptor(Crypto.prototype, 'subtle'), - enumerable: true, - }, + subtle: kEnumerableProperty, getRandomValues: { enumerable: true, configurable: true, diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index 2cdd453b15ba91..def0e9223b84c7 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -30,7 +30,8 @@ const kEncoder = Symbol('encoder'); const { getConstructorOf, - customInspectSymbol: inspect + customInspectSymbol: inspect, + kEnumerableProperty, } = require('internal/util'); const { @@ -358,9 +359,9 @@ class TextEncoder { ObjectDefineProperties( TextEncoder.prototype, { - 'encode': { enumerable: true }, - 'encodeInto': { enumerable: true }, - 'encoding': { enumerable: true }, + 'encode': kEnumerableProperty, + 'encodeInto': kEnumerableProperty, + 'encoding': kEnumerableProperty, [SymbolToStringTag]: { configurable: true, value: 'TextEncoder' }, }); @@ -569,7 +570,7 @@ ObjectDefineProperties( ); ObjectDefineProperties(TextDecoder.prototype, { - decode: { enumerable: true }, + decode: kEnumerableProperty, [inspect]: { enumerable: false }, [SymbolToStringTag]: { configurable: true, diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 3bc2fbb81cb20c..bc6f91fbe82159 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -8,7 +8,6 @@ const { FunctionPrototypeCall, NumberIsInteger, ObjectAssign, - ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, @@ -36,7 +35,7 @@ const { } = require('internal/errors'); const { validateObject, validateString } = require('internal/validators'); -const { customInspectSymbol } = require('internal/util'); +const { customInspectSymbol, kEnumerableProperty } = require('internal/util'); const { inspect } = require('util'); const kIsEventTarget = SymbolFor('nodejs.event_target'); @@ -298,9 +297,6 @@ class Event { static BUBBLING_PHASE = 3; } -const kEnumerableProperty = ObjectCreate(null); -kEnumerableProperty.enumerable = true; - ObjectDefineProperties( Event.prototype, { [SymbolToStringTag]: { diff --git a/lib/internal/url.js b/lib/internal/url.js index 3035c9c1979ed1..279519004f9207 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -43,6 +43,7 @@ const { getConstructorOf, removeColors, toUSVString, + kEnumerableProperty, } = require('internal/util'); const { @@ -507,18 +508,18 @@ class URLSearchParams { } ObjectDefineProperties(URLSearchParams.prototype, { - append: { enumerable: true }, - delete: { enumerable: true }, - get: { enumerable: true }, - getAll: { enumerable: true }, - has: { enumerable: true }, - set: { enumerable: true }, - sort: { enumerable: true }, - entries: { enumerable: true }, - forEach: { enumerable: true }, - keys: { enumerable: true }, - values: { enumerable: true }, - toString: { enumerable: true }, + append: kEnumerableProperty, + delete: kEnumerableProperty, + get: kEnumerableProperty, + getAll: kEnumerableProperty, + has: kEnumerableProperty, + set: kEnumerableProperty, + sort: kEnumerableProperty, + entries: kEnumerableProperty, + forEach: kEnumerableProperty, + keys: kEnumerableProperty, + values: kEnumerableProperty, + toString: kEnumerableProperty, [SymbolToStringTag]: { configurable: true, value: 'URLSearchParams' }, // https://heycam.github.io/webidl/#es-iterable-entries @@ -982,20 +983,20 @@ class URL { ObjectDefineProperties(URL.prototype, { [kFormat]: { configurable: false, writable: false }, [SymbolToStringTag]: { configurable: true, value: 'URL' }, - toString: { enumerable: true }, - href: { enumerable: true }, - origin: { enumerable: true }, - protocol: { enumerable: true }, - username: { enumerable: true }, - password: { enumerable: true }, - host: { enumerable: true }, - hostname: { enumerable: true }, - port: { enumerable: true }, - pathname: { enumerable: true }, - search: { enumerable: true }, - searchParams: { enumerable: true }, - hash: { enumerable: true }, - toJSON: { enumerable: true }, + toString: kEnumerableProperty, + href: kEnumerableProperty, + origin: kEnumerableProperty, + protocol: kEnumerableProperty, + username: kEnumerableProperty, + password: kEnumerableProperty, + host: kEnumerableProperty, + hostname: kEnumerableProperty, + port: kEnumerableProperty, + pathname: kEnumerableProperty, + search: kEnumerableProperty, + searchParams: kEnumerableProperty, + hash: kEnumerableProperty, + toJSON: kEnumerableProperty, }); function update(url, params) { diff --git a/lib/internal/util.js b/lib/internal/util.js index 38ebf910bd7dfb..d1b82fd69e1089 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -508,6 +508,9 @@ function structuredClone(value) { return des.readValue(); } +const kEnumerableProperty = ObjectCreate(null); +kEnumerableProperty.enumerable = true; + module.exports = { assertCrypto, cachedResult, @@ -546,5 +549,7 @@ module.exports = { // Used by the buffer module to capture an internal reference to the // default isEncoding implementation, just in case userland overrides it. kIsEncodingSymbol: Symbol('kIsEncodingSymbol'), - kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol') + kVmBreakFirstLineSymbol: Symbol('kVmBreakFirstLineSymbol'), + + kEnumerableProperty, }; diff --git a/lib/internal/webstreams/compression.js b/lib/internal/webstreams/compression.js new file mode 100644 index 00000000000000..2ba8e53fa28e73 --- /dev/null +++ b/lib/internal/webstreams/compression.js @@ -0,0 +1,162 @@ +'use strict'; + +const { + ObjectDefineProperties, + Symbol, +} = primordials; + +const { + codes: { + ERR_INVALID_ARG_VALUE, + ERR_INVALID_THIS, + }, +} = require('internal/errors'); + +const { + newReadableWritablePairFromDuplex, +} = require('internal/webstreams/adapters'); + +const { customInspect } = require('internal/webstreams/util'); + +const { + customInspectSymbol: kInspect, + kEnumerableProperty, +} = require('internal/util'); + +let zlib; +function lazyZlib() { + zlib ??= require('zlib'); + return zlib; +} + +const kHandle = Symbol('kHandle'); +const kTransform = Symbol('kTransform'); +const kType = Symbol('kType'); + +/** + * @typedef {import('./readablestream').ReadableStream} ReadableStream + * @typedef {import('./writablestream').WritableStream} WritableStream + */ + +function isCompressionStream(value) { + return typeof value?.[kHandle] === 'object' && + value?.[kType] === 'CompressionStream'; +} + +function isDecompressionStream(value) { + return typeof value?.[kHandle] === 'object' && + value?.[kType] === 'DecompressionStream'; +} + +class CompressionStream { + /** + * @param {'deflate'|'gzip'} format + */ + constructor(format) { + this[kType] = 'CompressionStream'; + switch (format) { + case 'deflate': + this[kHandle] = lazyZlib().createDeflate(); + break; + case 'gzip': + this[kHandle] = lazyZlib().createGzip(); + break; + default: + throw new ERR_INVALID_ARG_VALUE('format', format); + } + this[kTransform] = newReadableWritablePairFromDuplex(this[kHandle]); + } + + /** + * @readonly + * @type {ReadableStream} + */ + get readable() { + if (!isCompressionStream(this)) + throw new ERR_INVALID_THIS('CompressionStream'); + return this[kTransform].readable; + } + + /** + * @readonly + * @type {WritableStream} + */ + get writable() { + if (!isCompressionStream(this)) + throw new ERR_INVALID_THIS('CompressionStream'); + return this[kTransform].writable; + } + + [kInspect](depth, options) { + if (!isCompressionStream(this)) + throw new ERR_INVALID_THIS('CompressionStream'); + customInspect(depth, options, 'CompressionStream', { + readable: this[kTransform].readable, + writable: this[kTransform].writable, + }); + } +} + +class DecompressionStream { + /** + * @param {'deflate'|'gzip'} format + */ + constructor(format) { + this[kType] = 'DecompressionStream'; + switch (format) { + case 'deflate': + this[kHandle] = lazyZlib().createInflate(); + break; + case 'gzip': + this[kHandle] = lazyZlib().createGunzip(); + break; + default: + throw new ERR_INVALID_ARG_VALUE('format', format); + } + this[kTransform] = newReadableWritablePairFromDuplex(this[kHandle]); + } + + /** + * @readonly + * @type {ReadableStream} + */ + get readable() { + if (!isDecompressionStream(this)) + throw new ERR_INVALID_THIS('DecompressionStream'); + return this[kTransform].readable; + } + + /** + * @readonly + * @type {WritableStream} + */ + get writable() { + if (!isDecompressionStream(this)) + throw new ERR_INVALID_THIS('DecompressionStream'); + return this[kTransform].writable; + } + + [kInspect](depth, options) { + if (!isDecompressionStream(this)) + throw new ERR_INVALID_THIS('DecompressionStream'); + customInspect(depth, options, 'DecompressionStream', { + readable: this[kTransform].readable, + writable: this[kTransform].writable, + }); + } +} + +ObjectDefineProperties(CompressionStream.prototype, { + readable: kEnumerableProperty, + writable: kEnumerableProperty, +}); + +ObjectDefineProperties(DecompressionStream.prototype, { + readable: kEnumerableProperty, + writable: kEnumerableProperty, +}); + +module.exports = { + CompressionStream, + DecompressionStream, +}; diff --git a/lib/internal/webstreams/encoding.js b/lib/internal/webstreams/encoding.js index 5af59bc9f4a502..9cc76fae2ce10d 100644 --- a/lib/internal/webstreams/encoding.js +++ b/lib/internal/webstreams/encoding.js @@ -14,10 +14,7 @@ const { TransformStream, } = require('internal/webstreams/transformstream'); -const { - customInspect, - kEnumerableProperty, -} = require('internal/webstreams/util'); +const { customInspect } = require('internal/webstreams/util'); const { codes: { @@ -26,7 +23,8 @@ const { } = require('internal/errors'); const { - customInspectSymbol: kInspect + customInspectSymbol: kInspect, + kEnumerableProperty, } = require('internal/util'); const kHandle = Symbol('kHandle'); diff --git a/lib/internal/webstreams/queuingstrategies.js b/lib/internal/webstreams/queuingstrategies.js index cd8ec2bf35bfd0..78cec0c35559d3 100644 --- a/lib/internal/webstreams/queuingstrategies.js +++ b/lib/internal/webstreams/queuingstrategies.js @@ -14,6 +14,7 @@ const { const { customInspectSymbol: kInspect, + kEnumerableProperty, } = require('internal/util'); const { @@ -21,7 +22,6 @@ const { isBrandCheck, kType, kState, - kEnumerableProperty, } = require('internal/webstreams/util'); const { diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index 76200cbc1e876c..9853bd8b2cf2a3 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -50,6 +50,7 @@ const { const { createDeferredPromise, customInspectSymbol: kInspect, + kEnumerableProperty, } = require('internal/util'); const { @@ -109,7 +110,6 @@ const { nonOpStart, kType, kState, - kEnumerableProperty, } = require('internal/webstreams/util'); const { diff --git a/lib/internal/webstreams/transformstream.js b/lib/internal/webstreams/transformstream.js index e3cfd0362a26a5..457c9eb8fb338a 100644 --- a/lib/internal/webstreams/transformstream.js +++ b/lib/internal/webstreams/transformstream.js @@ -27,6 +27,7 @@ const { const { createDeferredPromise, customInspectSymbol: kInspect, + kEnumerableProperty, } = require('internal/util'); const { @@ -45,7 +46,6 @@ const { nonOpFlush, kType, kState, - kEnumerableProperty, } = require('internal/webstreams/util'); const { diff --git a/lib/internal/webstreams/util.js b/lib/internal/webstreams/util.js index 58f191cf07ff5a..305064ba05a490 100644 --- a/lib/internal/webstreams/util.js +++ b/lib/internal/webstreams/util.js @@ -207,9 +207,6 @@ function lazyTransfer() { return transfer; } -const kEnumerableProperty = ObjectCreate(null); -kEnumerableProperty.enumerable = true; - module.exports = { ArrayBufferViewGetBuffer, ArrayBufferViewGetByteLength, @@ -237,5 +234,4 @@ module.exports = { nonOpWrite, kType, kState, - kEnumerableProperty, }; diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js index fa0d3b78e3e1ea..8c25cc33c15f5f 100644 --- a/lib/internal/webstreams/writablestream.js +++ b/lib/internal/webstreams/writablestream.js @@ -33,6 +33,7 @@ const { const { createDeferredPromise, customInspectSymbol: kInspect, + kEnumerableProperty, } = require('internal/util'); const { @@ -64,7 +65,6 @@ const { nonOpWrite, kType, kState, - kEnumerableProperty, } = require('internal/webstreams/util'); const { diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js index 5d03f43ef6df62..a2d6fe42a32f1a 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -18,6 +18,8 @@ const { SymbolFor, } = primordials; +const { kEnumerableProperty } = require('internal/util'); + const { handle_onclose: handleOnCloseSymbol, oninit: onInitSymbol, @@ -481,9 +483,6 @@ class BroadcastChannel extends EventTarget { } } -const kEnumerableProperty = ObjectCreate(null); -kEnumerableProperty.enumerable = true; - ObjectDefineProperties(BroadcastChannel.prototype, { name: kEnumerableProperty, close: kEnumerableProperty,