diff --git a/lib/fetch/file.js b/lib/fetch/file.js index f7a588c9d0f..f27fc7fb7be 100644 --- a/lib/fetch/file.js +++ b/lib/fetch/file.js @@ -13,9 +13,7 @@ class File extends Blob { // The File constructor is invoked with two or three parameters, depending // on whether the optional dictionary parameter is used. When the File() // constructor is invoked, user agents must run the following steps: - if (arguments.length < 2) { - throw new TypeError('2 arguments required') - } + webidl.argumentLengthCheck(arguments, 2, { header: 'File constructor' }) fileBits = webidl.converters['sequence'](fileBits) fileName = webidl.converters.USVString(fileName) diff --git a/lib/fetch/formdata.js b/lib/fetch/formdata.js index a2d4ca1a4f5..5d0649ba92e 100644 --- a/lib/fetch/formdata.js +++ b/lib/fetch/formdata.js @@ -23,11 +23,7 @@ class FormData { append (name, value, filename = undefined) { webidl.brandCheck(this, FormData) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'append' on 'FormData': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.append' }) if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -56,11 +52,7 @@ class FormData { delete (name) { webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'delete' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.delete' }) name = webidl.converters.USVString(name) @@ -79,11 +71,7 @@ class FormData { get (name) { webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'get' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.get' }) name = webidl.converters.USVString(name) @@ -102,11 +90,7 @@ class FormData { getAll (name) { webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'getAll' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.getAll' }) name = webidl.converters.USVString(name) @@ -122,11 +106,7 @@ class FormData { has (name) { webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'has' on 'FormData': 1 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.has' }) name = webidl.converters.USVString(name) @@ -138,11 +118,7 @@ class FormData { set (name, value, filename = undefined) { webidl.brandCheck(this, FormData) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'set' on 'FormData': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'FormData.set' }) if (arguments.length === 3 && !isBlobLike(value)) { throw new TypeError( @@ -219,11 +195,7 @@ class FormData { forEach (callbackFn, thisArg = globalThis) { webidl.brandCheck(this, FormData) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'forEach' on 'FormData': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FormData.forEach' }) if (typeof callbackFn !== 'function') { throw new TypeError( diff --git a/lib/fetch/headers.js b/lib/fetch/headers.js index 962e8e8f7d0..680f9a06cd9 100644 --- a/lib/fetch/headers.js +++ b/lib/fetch/headers.js @@ -175,11 +175,7 @@ class Headers { append (name, value) { webidl.brandCheck(this, Headers) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'append' on 'Headers': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.append' }) name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) @@ -227,11 +223,7 @@ class Headers { delete (name) { webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'delete' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.delete' }) name = webidl.converters.ByteString(name) @@ -276,11 +268,7 @@ class Headers { get (name) { webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'get' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.get' }) name = webidl.converters.ByteString(name) @@ -302,11 +290,7 @@ class Headers { has (name) { webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'has' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.has' }) name = webidl.converters.ByteString(name) @@ -328,11 +312,7 @@ class Headers { set (name, value) { webidl.brandCheck(this, Headers) - if (arguments.length < 2) { - throw new TypeError( - `Failed to execute 'set' on 'Headers': 2 arguments required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 2, { header: 'Headers.set' }) name = webidl.converters.ByteString(name) value = webidl.converters.ByteString(value) @@ -421,11 +401,7 @@ class Headers { forEach (callbackFn, thisArg = globalThis) { webidl.brandCheck(this, Headers) - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'forEach' on 'Headers': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Headers.forEach' }) if (typeof callbackFn !== 'function') { throw new TypeError( diff --git a/lib/fetch/index.js b/lib/fetch/index.js index 4eafb2fee2d..6c67c1ee1b9 100644 --- a/lib/fetch/index.js +++ b/lib/fetch/index.js @@ -57,6 +57,7 @@ const { isErrored, isReadable } = require('../core/util') const { dataURLProcessor, serializeAMimeType } = require('./dataURL') const { TransformStream } = require('stream/web') const { getGlobalDispatcher } = require('../../index') +const { webidl } = require('./webidl') /** @type {import('buffer').resolveObjectURL} */ let resolveObjectURL @@ -122,11 +123,7 @@ class Fetch extends EE { // https://fetch.spec.whatwg.org/#fetch-method async function fetch (input, init = {}) { - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'fetch' on 'Window': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'globalThis.fetch' }) // 1. Let p be a new promise. const p = createDeferredPromise() diff --git a/lib/fetch/request.js b/lib/fetch/request.js index 40e54d27ab6..29e901256f6 100644 --- a/lib/fetch/request.js +++ b/lib/fetch/request.js @@ -45,11 +45,7 @@ class Request { return } - if (arguments.length < 1) { - throw new TypeError( - `Failed to construct 'Request': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Request constructor' }) input = webidl.converters.RequestInfo(input) init = webidl.converters.RequestInit(init) diff --git a/lib/fetch/response.js b/lib/fetch/response.js index d3151d88d40..9c9d6284d78 100644 --- a/lib/fetch/response.js +++ b/lib/fetch/response.js @@ -50,11 +50,7 @@ class Response { // https://fetch.spec.whatwg.org/#dom-response-json static json (data = undefined, init = {}) { - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'json\' on \'Response\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Response.json' }) if (init !== null) { init = webidl.converters.ResponseInit(init) @@ -87,11 +83,7 @@ class Response { static redirect (url, status = 302) { const relevantRealm = { settingsObject: {} } - if (arguments.length < 1) { - throw new TypeError( - `Failed to execute 'redirect' on 'Response': 1 argument required, but only ${arguments.length} present.` - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'Response.redirect' }) url = webidl.converters.USVString(url) status = webidl.converters['unsigned short'](status) diff --git a/lib/fetch/webidl.js b/lib/fetch/webidl.js index 31dcb1ddfa6..32c1befab00 100644 --- a/lib/fetch/webidl.js +++ b/lib/fetch/webidl.js @@ -39,6 +39,16 @@ webidl.brandCheck = function (V, I) { } } +webidl.argumentLengthCheck = function ({ length }, min, ctx) { + if (length < min) { + throw webidl.errors.exception({ + message: `${min} argument${min !== 1 ? 's' : ''} required, ` + + `but${length ? ' only' : ''} ${length} found.`, + ...ctx + }) + } +} + // https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values webidl.util.Type = function (V) { switch (typeof V) { @@ -98,7 +108,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { let x = Number(V) // 5. If x is −0, then set x to +0. - if (Object.is(-0, x)) { + if (x === 0) { x = 0 } @@ -156,7 +166,7 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, opts = {}) { // 8. If x is NaN, +0, +∞, or −∞, then return +0. if ( Number.isNaN(x) || - Object.is(0, x) || + (x === 0 && Object.is(0, x)) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY ) { diff --git a/lib/fileapi/filereader.js b/lib/fileapi/filereader.js index 2bc2c46ac6a..9a8bdd90335 100644 --- a/lib/fileapi/filereader.js +++ b/lib/fileapi/filereader.js @@ -39,11 +39,7 @@ class FileReader extends EventTarget { readAsArrayBuffer (blob) { webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsArrayBuffer\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsArrayBuffer' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -59,11 +55,7 @@ class FileReader extends EventTarget { readAsBinaryString (blob) { webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsBinaryString\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsBinaryString' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -80,11 +72,7 @@ class FileReader extends EventTarget { readAsText (blob, encoding = undefined) { webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsText\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsText' }) blob = webidl.converters.Blob(blob, { strict: false }) @@ -104,11 +92,7 @@ class FileReader extends EventTarget { readAsDataURL (blob) { webidl.brandCheck(this, FileReader) - if (arguments.length === 0) { - throw new TypeError( - 'Failed to execute \'readAsDataURL\' on \'FileReader\': 1 argument required, but 0 present.' - ) - } + webidl.argumentLengthCheck(arguments, 1, { header: 'FileReader.readAsDataURL' }) blob = webidl.converters.Blob(blob, { strict: false }) diff --git a/types/webidl.d.ts b/types/webidl.d.ts index c284c44ea3e..1b49fd6d769 100644 --- a/types/webidl.d.ts +++ b/types/webidl.d.ts @@ -205,4 +205,9 @@ export interface Webidl { nullableConverter ( converter: Converter ): (V: unknown) => ReturnType | null + + argumentLengthCheck (args: { length: number }, min: number, context: { + header: string + message?: string + }): void }