From 486eafc6dc23b6bec0e76ba133eff5bf14da08b8 Mon Sep 17 00:00:00 2001 From: Khafra Date: Wed, 28 Aug 2024 11:08:18 -0400 Subject: [PATCH] change webidl.util.Type return to an enum value --- lib/web/fetch/headers.js | 2 +- lib/web/fetch/webidl.js | 69 +++++++++++++++++++++++++--------- lib/web/websocket/websocket.js | 6 +-- test/webidl/converters.js | 9 +++++ test/webidl/util.js | 20 +++++----- types/webidl.d.ts | 17 ++++++++- 6 files changed, 91 insertions(+), 32 deletions(-) diff --git a/lib/web/fetch/headers.js b/lib/web/fetch/headers.js index 816aceacce4..6f51f36a58b 100644 --- a/lib/web/fetch/headers.js +++ b/lib/web/fetch/headers.js @@ -645,7 +645,7 @@ Object.defineProperties(Headers.prototype, { }) webidl.converters.HeadersInit = function (V, prefix, argument) { - if (webidl.util.Type(V) === 'Object') { + if (webidl.util.Type(V) === webidl.util.Types.OBJECT) { const iterator = Reflect.get(V, Symbol.iterator) // A work-around to ensure we send the properly-cased Headers when V is a Headers object. diff --git a/lib/web/fetch/webidl.js b/lib/web/fetch/webidl.js index d3cc4791550..5397344e57b 100644 --- a/lib/web/fetch/webidl.js +++ b/lib/web/fetch/webidl.js @@ -3,6 +3,15 @@ const { types, inspect } = require('node:util') const { toUSVString } = require('../../core/util') +const UNDEFINED = 1 +const BOOLEAN = 2 +const STRING = 3 +const SYMBOL = 4 +const NUMBER = 5 +const BIGINT = 6 +const NULL = 7 +const OBJECT = 8 // function and object + /** @type {import('../../../types/webidl').Webidl} */ const webidl = {} webidl.converters = {} @@ -69,23 +78,47 @@ webidl.illegalConstructor = function () { // https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values webidl.util.Type = function (V) { switch (typeof V) { - case 'undefined': return 'Undefined' - case 'boolean': return 'Boolean' - case 'string': return 'String' - case 'symbol': return 'Symbol' - case 'number': return 'Number' - case 'bigint': return 'BigInt' + case 'undefined': return UNDEFINED + case 'boolean': return BOOLEAN + case 'string': return STRING + case 'symbol': return SYMBOL + case 'number': return NUMBER + case 'bigint': return BIGINT case 'function': case 'object': { if (V === null) { - return 'Null' + return NULL } - return 'Object' + return OBJECT } } } +webidl.util.Types = { + UNDEFINED, + BOOLEAN, + STRING, + SYMBOL, + NUMBER, + BIGINT, + NULL, + OBJECT +} + +webidl.util.TypeValueToString = function (o) { + switch (webidl.util.Type(o)) { + case UNDEFINED: return 'Undefined' + case BOOLEAN: return 'Boolean' + case STRING: return 'String' + case SYMBOL: return 'Symbol' + case NUMBER: return 'Number' + case BIGINT: return 'BigInt' + case NULL: return 'Null' + case OBJECT: return 'Object' + } +} + // https://webidl.spec.whatwg.org/#abstract-opdef-converttoint webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) { let upperBound @@ -224,11 +257,11 @@ webidl.util.Stringify = function (V) { const type = webidl.util.Type(V) switch (type) { - case 'Symbol': + case SYMBOL: return `Symbol(${V.description})` - case 'Object': + case OBJECT: return inspect(V) - case 'String': + case STRING: return `"${V}"` default: return `${V}` @@ -239,7 +272,7 @@ webidl.util.Stringify = function (V) { webidl.sequenceConverter = function (converter) { return (V, prefix, argument, Iterable) => { // 1. If Type(V) is not Object, throw a TypeError. - if (webidl.util.Type(V) !== 'Object') { + if (webidl.util.Type(V) !== OBJECT) { throw webidl.errors.exception({ header: prefix, message: `${argument} (${webidl.util.Stringify(V)}) is not iterable.` @@ -282,10 +315,10 @@ webidl.sequenceConverter = function (converter) { webidl.recordConverter = function (keyConverter, valueConverter) { return (O, prefix, argument) => { // 1. If Type(O) is not Object, throw a TypeError. - if (webidl.util.Type(O) !== 'Object') { + if (webidl.util.Type(O) !== OBJECT) { throw webidl.errors.exception({ header: prefix, - message: `${argument} ("${webidl.util.Type(O)}") is not an Object.` + message: `${argument} ("${webidl.util.TypeValueToString(O)}") is not an Object.` }) } @@ -356,7 +389,7 @@ webidl.dictionaryConverter = function (converters) { return (dictionary, prefix, argument) => { const dict = {} - if (dictionary != null && webidl.util.Type(dictionary) !== 'Object') { + if (dictionary != null && webidl.util.Type(dictionary) !== OBJECT) { throw webidl.errors.exception({ header: prefix, message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` @@ -532,7 +565,7 @@ webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) { // see: https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-instances // see: https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-instances if ( - webidl.util.Type(V) !== 'Object' || + webidl.util.Type(V) !== OBJECT || !types.isAnyArrayBuffer(V) ) { throw webidl.errors.conversionFailed({ @@ -576,7 +609,7 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) { // [[TypedArrayName]] internal slot with a value // equal to T’s name, then throw a TypeError. if ( - webidl.util.Type(V) !== 'Object' || + webidl.util.Type(V) !== OBJECT || !types.isTypedArray(V) || V.constructor.name !== T.name ) { @@ -617,7 +650,7 @@ webidl.converters.TypedArray = function (V, T, prefix, name, opts) { webidl.converters.DataView = function (V, prefix, name, opts) { // 1. If Type(V) is not Object, or V does not have a // [[DataView]] internal slot, then throw a TypeError. - if (webidl.util.Type(V) !== 'Object' || !types.isDataView(V)) { + if (webidl.util.Type(V) !== OBJECT || !types.isDataView(V)) { throw webidl.errors.exception({ header: prefix, message: `${name} is not a DataView.` diff --git a/lib/web/websocket/websocket.js b/lib/web/websocket/websocket.js index 5d876987e16..2b50c753df2 100644 --- a/lib/web/websocket/websocket.js +++ b/lib/web/websocket/websocket.js @@ -758,7 +758,7 @@ webidl.converters['sequence'] = webidl.sequenceConverter( ) webidl.converters['DOMString or sequence'] = function (V, prefix, argument) { - if (webidl.util.Type(V) === 'Object' && Symbol.iterator in V) { + if (webidl.util.Type(V) === webidl.util.Types.OBJECT && Symbol.iterator in V) { return webidl.converters['sequence'](V) } @@ -784,7 +784,7 @@ webidl.converters.WebSocketInit = webidl.dictionaryConverter([ ]) webidl.converters['DOMString or sequence or WebSocketInit'] = function (V) { - if (webidl.util.Type(V) === 'Object' && !(Symbol.iterator in V)) { + if (webidl.util.Type(V) === webidl.util.Types.OBJECT && !(Symbol.iterator in V)) { return webidl.converters.WebSocketInit(V) } @@ -792,7 +792,7 @@ webidl.converters['DOMString or sequence or WebSocketInit'] = functio } webidl.converters.WebSocketSendData = function (V) { - if (webidl.util.Type(V) === 'Object') { + if (webidl.util.Type(V) === webidl.util.Types.OBJECT) { if (V instanceof Blob) { return V } diff --git a/test/webidl/converters.js b/test/webidl/converters.js index ccc376a7ab9..722910d9b56 100644 --- a/test/webidl/converters.js +++ b/test/webidl/converters.js @@ -238,3 +238,12 @@ test('webidl.util.Stringify', (t) => { assert.deepStrictEqual(webidl.util.Stringify(value), expected) } }) + +test('recordConverter', () => { + const anyConverter = webidl.recordConverter(webidl.converters.any, webidl.converters.any) + + assert.throws( + () => anyConverter(null, 'prefix', 'argument'), + new TypeError('prefix: argument ("Null") is not an Object.') + ) +}) diff --git a/test/webidl/util.js b/test/webidl/util.js index 83ea669fb2f..267497774b2 100644 --- a/test/webidl/util.js +++ b/test/webidl/util.js @@ -6,15 +6,17 @@ const { webidl } = require('../../lib/web/fetch/webidl') test('Type(V)', () => { const Type = webidl.util.Type - - assert.equal(Type(undefined), 'Undefined') - assert.equal(Type(null), 'Null') - assert.equal(Type(true), 'Boolean') - assert.equal(Type('string'), 'String') - assert.equal(Type(Symbol('symbol')), 'Symbol') - assert.equal(Type(1.23), 'Number') - assert.equal(Type(1n), 'BigInt') - assert.equal(Type({ a: 'b' }), 'Object') + const Types = webidl.util.Types + + assert.equal(Type(undefined), Types.UNDEFINED) + assert.equal(Type(null), Types.NULL) + assert.equal(Type(true), Types.BOOLEAN) + assert.equal(Type('string'), Types.STRING) + assert.equal(Type(Symbol('symbol')), Types.SYMBOL) + assert.equal(Type(1.23), Types.NUMBER) + assert.equal(Type(1n), Types.BIGINT) + assert.equal(Type({ a: 'b' }), Types.OBJECT) + assert.equal(Type(function () {}), Types.OBJECT) }) test('ConvertToInt(V)', () => { diff --git a/types/webidl.d.ts b/types/webidl.d.ts index eebe99c801c..c42a2617fd2 100644 --- a/types/webidl.d.ts +++ b/types/webidl.d.ts @@ -34,11 +34,24 @@ interface WebidlErrors { }): TypeError } +interface WebIDLTypes { + UNDEFINED: 1, + BOOLEAN: 2, + STRING: 3, + SYMBOL: 4, + NUMBER: 5, + BIGINT: 6, + NULL: 7 + OBJECT: 8 +} + interface WebidlUtil { /** * @see https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values */ - Type (object: unknown): + Type (object: unknown): WebIDLTypes + + TypeValueToString (o: unknown): | 'Undefined' | 'Boolean' | 'String' @@ -48,6 +61,8 @@ interface WebidlUtil { | 'Null' | 'Object' + Types: WebIDLTypes + /** * @see https://webidl.spec.whatwg.org/#abstract-opdef-converttoint */