From 29f7256c688bbc23ba26ca6bbfa61609cb58dbf4 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 00:15:43 +0200 Subject: [PATCH 01/12] Support SharedArrayBuffer type --- lib/output/utils.js | 16 ++- lib/parameters.js | 11 ++ lib/types.js | 12 +- test/__snapshots__/test.js.snap | 170 ++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 2 + test/cases/TypedefsAndUnions.webidl | 1 + 6 files changed, 209 insertions(+), 3 deletions(-) diff --git a/lib/output/utils.js b/lib/output/utils.js index fafd6a71..5e509791 100644 --- a/lib/output/utils.js +++ b/lib/output/utils.js @@ -110,11 +110,22 @@ function isArrayIndexPropName(P) { return true; } -const byteLengthGetter = +const arrayBufferByteLengthGetter = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get; function isArrayBuffer(value) { try { - byteLengthGetter.call(value); + arrayBufferByteLengthGetter.call(value); + return true; + } catch { + return false; + } +} + +const sharedArrayBufferByteLengthGetter = + Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, "byteLength").get; +function isSharedArrayBuffer(value) { + try { + sharedArrayBufferByteLengthGetter.call(value); return true; } catch { return false; @@ -219,6 +230,7 @@ module.exports = exports = { tryImplForWrapper, iterInternalSymbol, isArrayBuffer, + isSharedArrayBuffer, isArrayIndexPropName, supportsPropertyIndex, supportedPropertyIndices, diff --git a/lib/parameters.js b/lib/parameters.js index ca525259..0df2ebfc 100644 --- a/lib/parameters.js +++ b/lib/parameters.js @@ -205,6 +205,17 @@ module.exports.generateOverloadConversions = function (ctx, typeOfOp, name, pare `); } + const sharedArrayBuffers = S.filter(o => { + return isOrIncludes(ctx, o.typeList[d], t => t.idlType === "SharedArrayBuffer"); + }); + if (sharedArrayBuffers.length) { + possibilities.push(` + if (utils.isSharedArrayBuffer(curArg)) { + ${continued(sharedArrayBuffers[0], i)} + } + `); + } + const arrayBufferViews = new Map(); for (const o of S) { const type = Types.resolveType(ctx, o.typeList[d]); diff --git a/lib/types.js b/lib/types.js index c5ea476e..a8373715 100644 --- a/lib/types.js +++ b/lib/types.js @@ -218,6 +218,9 @@ function generateTypeConversion( if (union.ArrayBuffer || union.object) { output.push(`if (utils.isArrayBuffer(${name})) {}`); } + if (union.SharedArrayBuffer || union.object) { + output.push(`if (utils.isSharedArrayBuffer(${name})) {}`); + } if (union.ArrayBufferViews.size > 0 || union.object) { let condition = `ArrayBuffer.isView(${name})`; // Skip specific type check if all ArrayBufferView member types are allowed. @@ -473,9 +476,10 @@ function extractUnionInfo(ctx, idlType, errPrefix) { return this.dictionary !== null || this.record !== null || this.callbackInterface !== null; }, ArrayBuffer: false, + SharedArrayBuffer: false, ArrayBufferViews: new Set(), get BufferSource() { - return this.ArrayBuffer || this.ArrayBufferViews.size > 0; + return this.ArrayBuffer || this.SharedArrayBuffer || this.ArrayBufferViews.size > 0; }, object: false, string: null, @@ -518,6 +522,11 @@ function extractUnionInfo(ctx, idlType, errPrefix) { error("ArrayBuffer is not distinguishable with object type"); } seen.ArrayBuffer = true; + } else if (item.idlType === "SharedArrayBuffer") { + if (seen.object) { + error("SharedArrayBuffer is not distinguishable with object type"); + } + seen.SharedArrayBuffer = true; } else if (arrayBufferViewTypes.has(item.idlType)) { if (seen.object) { error(`${item.idlType} is not distinguishable with object type`); @@ -665,6 +674,7 @@ function sameType(ctx, type1, type2) { return sameType(ctx, extracted1.sequenceLike, extracted2.sequenceLike) && sameType(ctx, extracted1.record, extracted2.record) && extracted1.ArrayBuffer !== extracted2.ArrayBuffer && + extracted1.SharedArrayBuffer !== extracted2.SharedArrayBuffer && JSON.stringify([...extracted1.ArrayBufferViews].sort()) === JSON.stringify([...extracted2.ArrayBufferViews].sort()) && extracted1.object === extracted2.object && diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 1c707a65..d3b02edc 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1415,6 +1415,31 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].ab(...args); } + sab(sab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'sab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'sab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'sab' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + args.push(curArg); + } + return esValue[implSymbol].sab(...args); + } + abv(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -1495,6 +1520,34 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].abUnion(...args); } + sabUnion(ab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'sabUnion' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'sabUnion' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isSharedArrayBuffer(curArg)) { + } else { + curArg = conversions["DOMString"](curArg, { + context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].sabUnion(...args); + } + u8aUnion(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -1526,9 +1579,11 @@ exports.install = (globalObject, globalNames) => { Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, ab: { enumerable: true }, + sab: { enumerable: true }, abv: { enumerable: true }, u8a: { enumerable: true }, abUnion: { enumerable: true }, + sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); @@ -8391,6 +8446,35 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].arrayBufferViewDupConsumer(...args); } + arrayBufferOrSharedArrayBufferConsumer(b) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arrayBufferOrSharedArrayBufferConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + } else if (utils.isSharedArrayBuffer(curArg)) { + } else { + throw new globalObject.TypeError( + "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1" + + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arrayBufferOrSharedArrayBufferConsumer(...args); + } + get buf() { const esValue = this !== null && this !== undefined ? this : globalObject; @@ -8465,6 +8549,7 @@ exports.install = (globalObject, globalNames) => { bufferSourceOrURLConsumer: { enumerable: true }, arrayBufferViewOrURLMapConsumer: { enumerable: true }, arrayBufferViewDupConsumer: { enumerable: true }, + arrayBufferOrSharedArrayBufferConsumer: { enumerable: true }, buf: { enumerable: true }, time: { enumerable: true }, [Symbol.toStringTag]: { value: "TypedefsAndUnions", configurable: true } @@ -12583,6 +12668,31 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].ab(...args); } + sab(sab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'sab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'sab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'sab' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + args.push(curArg); + } + return esValue[implSymbol].sab(...args); + } + abv(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -12663,6 +12773,34 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].abUnion(...args); } + sabUnion(ab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'sabUnion' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'sabUnion' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isSharedArrayBuffer(curArg)) { + } else { + curArg = conversions["DOMString"](curArg, { + context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].sabUnion(...args); + } + u8aUnion(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -12694,9 +12832,11 @@ exports.install = (globalObject, globalNames) => { Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, ab: { enumerable: true }, + sab: { enumerable: true }, abv: { enumerable: true }, u8a: { enumerable: true }, abUnion: { enumerable: true }, + sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); @@ -19502,6 +19642,35 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].arrayBufferViewDupConsumer(...args); } + arrayBufferOrSharedArrayBufferConsumer(b) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arrayBufferOrSharedArrayBufferConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + } else if (utils.isSharedArrayBuffer(curArg)) { + } else { + throw new globalObject.TypeError( + "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1" + + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arrayBufferOrSharedArrayBufferConsumer(...args); + } + get buf() { const esValue = this !== null && this !== undefined ? this : globalObject; @@ -19576,6 +19745,7 @@ exports.install = (globalObject, globalNames) => { bufferSourceOrURLConsumer: { enumerable: true }, arrayBufferViewOrURLMapConsumer: { enumerable: true }, arrayBufferViewDupConsumer: { enumerable: true }, + arrayBufferOrSharedArrayBufferConsumer: { enumerable: true }, buf: { enumerable: true }, time: { enumerable: true }, [Symbol.toStringTag]: { value: "TypedefsAndUnions", configurable: true } diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index 26d7ef9b..e8a7e2ed 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -2,9 +2,11 @@ interface BufferSourceTypes { undefined bs(BufferSource source); undefined ab(ArrayBuffer ab); + undefined sab(SharedArrayBuffer sab); undefined abv(ArrayBufferView abv); undefined u8a(Uint8Array u8); undefined abUnion((ArrayBuffer or DOMString) ab); + undefined sabUnion((SharedArrayBuffer or DOMString) ab); undefined u8aUnion((Uint8Array or DOMString) ab); }; diff --git a/test/cases/TypedefsAndUnions.webidl b/test/cases/TypedefsAndUnions.webidl index 35420208..0e9edea9 100644 --- a/test/cases/TypedefsAndUnions.webidl +++ b/test/cases/TypedefsAndUnions.webidl @@ -9,6 +9,7 @@ interface TypedefsAndUnions { undefined bufferSourceOrURLConsumer((BufferSource or URL) b); undefined arrayBufferViewOrURLMapConsumer((ArrayBufferView or URLMap) b); undefined arrayBufferViewDupConsumer((ArrayBufferView or Uint8ClampedArray) b); + undefined arrayBufferOrSharedArrayBufferConsumer((ArrayBuffer or SharedArrayBuffer) b); attribute (ArrayBuffer or Uint8Array or Uint16Array) buf; attribute DOMTimeStamp time; From 06b4b137b74f332a9b937676d511b8e11394b736 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 00:29:17 +0200 Subject: [PATCH 02/12] Generate conversions for ArrayBuffer and SharedArrayBuffer --- lib/types.js | 21 ++++---- test/__snapshots__/test.js.snap | 88 +++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 9 deletions(-) diff --git a/lib/types.js b/lib/types.js index a8373715..bc986896 100644 --- a/lib/types.js +++ b/lib/types.js @@ -214,12 +214,15 @@ function generateTypeConversion( `); } - // Do not convert buffer source types as the impl code can either "get a reference" or "get a copy" to the bytes. if (union.ArrayBuffer || union.object) { - output.push(`if (utils.isArrayBuffer(${name})) {}`); + output.push(`if (utils.isArrayBuffer(${name})) { + ${generateTypeConversion(ctx, name, union.ArrayBuffer, [], parentName, errPrefix).body} + }`); } if (union.SharedArrayBuffer || union.object) { - output.push(`if (utils.isSharedArrayBuffer(${name})) {}`); + output.push(`if (utils.isSharedArrayBuffer(${name})) { + ${generateTypeConversion(ctx, name, union.SharedArrayBuffer, [], parentName, errPrefix).body} + }`); } if (union.ArrayBufferViews.size > 0 || union.object) { let condition = `ArrayBuffer.isView(${name})`; @@ -475,8 +478,8 @@ function extractUnionInfo(ctx, idlType, errPrefix) { get dictionaryLike() { return this.dictionary !== null || this.record !== null || this.callbackInterface !== null; }, - ArrayBuffer: false, - SharedArrayBuffer: false, + ArrayBuffer: null, + SharedArrayBuffer: null, ArrayBufferViews: new Set(), get BufferSource() { return this.ArrayBuffer || this.SharedArrayBuffer || this.ArrayBufferViews.size > 0; @@ -521,12 +524,12 @@ function extractUnionInfo(ctx, idlType, errPrefix) { if (seen.object) { error("ArrayBuffer is not distinguishable with object type"); } - seen.ArrayBuffer = true; + seen.ArrayBuffer = item; } else if (item.idlType === "SharedArrayBuffer") { if (seen.object) { error("SharedArrayBuffer is not distinguishable with object type"); } - seen.SharedArrayBuffer = true; + seen.SharedArrayBuffer = item; } else if (arrayBufferViewTypes.has(item.idlType)) { if (seen.object) { error(`${item.idlType} is not distinguishable with object type`); @@ -673,8 +676,8 @@ function sameType(ctx, type1, type2) { const extracted2 = extractUnionInfo(ctx, type2, `""`); return sameType(ctx, extracted1.sequenceLike, extracted2.sequenceLike) && sameType(ctx, extracted1.record, extracted2.record) && - extracted1.ArrayBuffer !== extracted2.ArrayBuffer && - extracted1.SharedArrayBuffer !== extracted2.SharedArrayBuffer && + sameType(ctx, extracted1.ArrayBuffer, extracted2.ArrayBuffer) && + sameType(ctx, extracted1.SharedArrayBuffer, extracted2.SharedArrayBuffer) && JSON.stringify([...extracted1.ArrayBufferViews].sort()) === JSON.stringify([...extracted2.ArrayBufferViews].sort()) && extracted1.object === extracted2.object && diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index d3b02edc..1c3e4ea0 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1381,6 +1381,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -1509,6 +1513,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'abUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'abUnion' on 'BufferSourceTypes': parameter 1", @@ -1537,6 +1545,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", @@ -5702,6 +5714,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[1]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -5714,6 +5730,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[1]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -5759,6 +5779,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[2]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 3", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -5770,6 +5794,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[3]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 4", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -8338,6 +8366,10 @@ exports.install = (globalObject, globalNames) => { if (URL.is(curArg)) { curArg = utils.implForWrapper(curArg); } else if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -8463,7 +8495,15 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -8497,6 +8537,10 @@ exports.install = (globalObject, globalNames) => { } if (utils.isArrayBuffer(V)) { + V = conversions["ArrayBuffer"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); } else if ( ArrayBuffer.isView(V) && (V.constructor.name === "Uint8Array" || V.constructor.name === "Uint16Array") @@ -12634,6 +12678,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -12762,6 +12810,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'abUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'abUnion' on 'BufferSourceTypes': parameter 1", @@ -12790,6 +12842,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'sabUnion' on 'BufferSourceTypes': parameter 1", @@ -16913,6 +16969,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[1]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -16925,6 +16985,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[1]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -16970,6 +17034,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[2]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 3", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -16981,6 +17049,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[3]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 4", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -19534,6 +19606,10 @@ exports.install = (globalObject, globalNames) => { if (URL.is(curArg)) { curArg = utils.implForWrapper(curArg); } else if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (ArrayBuffer.isView(curArg)) { } else { throw new globalObject.TypeError( @@ -19659,7 +19735,15 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'arrayBufferOrSharedArrayBufferConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -19693,6 +19777,10 @@ exports.install = (globalObject, globalNames) => { } if (utils.isArrayBuffer(V)) { + V = conversions["ArrayBuffer"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); } else if ( ArrayBuffer.isView(V) && (V.constructor.name === "Uint8Array" || V.constructor.name === "Uint16Array") From dc88f594312eee766c74caab7db6c1d4cf66e890 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 00:36:37 +0200 Subject: [PATCH 03/12] Support [AllowResizable] on ArrayBuffer and SharedArrayBuffer --- lib/types.js | 4 ++ test/__snapshots__/test.js.snap | 108 ++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 3 + 3 files changed, 115 insertions(+) diff --git a/lib/types.js b/lib/types.js index bc986896..16b4c618 100644 --- a/lib/types.js +++ b/lib/types.js @@ -427,6 +427,7 @@ function generateTypeConversion( const enforceRange = utils.getExtAttr(extAttrs, "EnforceRange"); const clamp = utils.getExtAttr(extAttrs, "Clamp"); const nullToEmptyString = utils.getExtAttr(extAttrs, "LegacyNullToEmptyString"); + const allowResizable = utils.getExtAttr(extAttrs, "AllowResizable"); let optString = `context: ${errPrefix}, globals: globalObject,`; if (clamp) { @@ -438,6 +439,9 @@ function generateTypeConversion( if (nullToEmptyString) { optString += "treatNullAsEmptyString: true,"; } + if (allowResizable) { + optString += "allowResizable: true,"; + } if (idlType.array) { str += ` for (let i = 0; i < ${name}.length; ++i) { diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 1c3e4ea0..3e646fcc 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1587,6 +1587,58 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].u8aUnion(...args); } + + arab(ab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arab' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].arab(...args); + } + + arsab(sab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arsab' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].arsab(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -1597,6 +1649,8 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + arab: { enumerable: true }, + arsab: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; @@ -12884,6 +12938,58 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].u8aUnion(...args); } + + arab(ab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arab' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].arab(...args); + } + + arsab(sab) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsab' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arsab' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].arsab(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -12894,6 +13000,8 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + arab: { enumerable: true }, + arsab: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index e8a7e2ed..82fb5ac6 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -9,4 +9,7 @@ interface BufferSourceTypes { undefined abUnion((ArrayBuffer or DOMString) ab); undefined sabUnion((SharedArrayBuffer or DOMString) ab); undefined u8aUnion((Uint8Array or DOMString) ab); + + undefined arab([AllowResizable] ArrayBuffer ab); + undefined arsab([AllowResizable] SharedArrayBuffer sab); }; From e87dcd9976fbd67e11698ed90be7ba20eefd5d56 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:03:46 +0200 Subject: [PATCH 04/12] Generate conversions for ArrayBufferView types Previously, ArrayBufferView objects were always returned as-is. However, we now need to emit dedicated conversions to support extended attributes such as [AllowResizable] and [AllowShared]. See https://webidl.spec.whatwg.org/#js-buffer-source-types --- lib/types.js | 41 +++++++----- test/__snapshots__/test.js.snap | 108 +++++++++++++++++++++++++++++--- 2 files changed, 124 insertions(+), 25 deletions(-) diff --git a/lib/types.js b/lib/types.js index 16b4c618..9621530c 100644 --- a/lib/types.js +++ b/lib/types.js @@ -142,7 +142,7 @@ function generateTypeConversion( generateFrozenArray(); } else if (conversions[idlType.idlType]) { // string or number type compatible with webidl-conversions - generateWebIDLConversions(`conversions["${idlType.idlType}"]`); + str += generateWebIDLConversions(`conversions["${idlType.idlType}"]`); } else if (resolvedTypes.has(ctx.typeOf(idlType.idlType))) { // callback functions, callback interfaces, dictionaries, enumerations, and interfaces let fn; @@ -225,13 +225,21 @@ function generateTypeConversion( }`); } if (union.ArrayBufferViews.size > 0 || union.object) { - let condition = `ArrayBuffer.isView(${name})`; + const viewIdlTypes = new Set([...union.ArrayBufferViews].map(item => item.idlType)); // Skip specific type check if all ArrayBufferView member types are allowed. - if (union.ArrayBufferViews.size !== arrayBufferViewTypes.size) { - const exprs = [...union.ArrayBufferViews].map(a => `${name}.constructor.name === "${a}"`); - condition += ` && (${exprs.join(" || ")})`; + if (viewIdlTypes.size === arrayBufferViewTypes.size) { + // We can't call generateTypeConversion since that will just expand the union again and recurse back to here, + // so instead we call generateWebIDLConversions directly. + output.push(`if (ArrayBuffer.isView(${name})) { + ${generateWebIDLConversions(`conversions["ArrayBufferView"]`)} + }`); + } else { + for (const viewType of union.ArrayBufferViews) { + output.push(`if (ArrayBuffer.isView(${name}) && ${name}.constructor.name === "${viewType.idlType}") { + ${generateTypeConversion(ctx, name, viewType, [], parentName, errPrefix).body} + }`); + } } - output.push(`if (${condition}) {}`); } if (union.callbackFunction || union.object) { @@ -423,11 +431,11 @@ function generateTypeConversion( str += `${name} = Object.freeze(${name});`; } - function generateWebIDLConversions(conversionFn) { - const enforceRange = utils.getExtAttr(extAttrs, "EnforceRange"); - const clamp = utils.getExtAttr(extAttrs, "Clamp"); - const nullToEmptyString = utils.getExtAttr(extAttrs, "LegacyNullToEmptyString"); - const allowResizable = utils.getExtAttr(extAttrs, "AllowResizable"); + function generateWebIDLConversions(conversionFn, attrs) { + const enforceRange = utils.getExtAttr(attrs, "EnforceRange"); + const clamp = utils.getExtAttr(attrs, "Clamp"); + const nullToEmptyString = utils.getExtAttr(attrs, "LegacyNullToEmptyString"); + const allowResizable = utils.getExtAttr(attrs, "AllowResizable"); let optString = `context: ${errPrefix}, globals: globalObject,`; if (clamp) { @@ -443,16 +451,15 @@ function generateTypeConversion( optString += "allowResizable: true,"; } if (idlType.array) { - str += ` + return ` for (let i = 0; i < ${name}.length; ++i) { ${name}[i] = ${conversionFn}(${name}[i], { ${optString} }); } `; - } else { - str += ` - ${name} = ${conversionFn}(${name}, { ${optString} }); - `; } + return ` + ${name} = ${conversionFn}(${name}, { ${optString} }); + `; } function generateWebIDL2JS(conversionFn) { @@ -538,7 +545,7 @@ function extractUnionInfo(ctx, idlType, errPrefix) { if (seen.object) { error(`${item.idlType} is not distinguishable with object type`); } - seen.ArrayBufferViews.add(item.idlType); + seen.ArrayBufferViews.add(item); } else if (stringTypes.has(item.idlType) || ctx.enumerations.has(item.idlType)) { if (seen.string) { error("There can only be one string type in a union type"); diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 3e646fcc..91a78e48 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1386,6 +1386,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." @@ -1461,6 +1465,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'abv' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'abv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." @@ -1577,6 +1585,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg) && curArg.constructor.name === "Uint8Array") { + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'u8aUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'u8aUnion' on 'BufferSourceTypes': parameter 1", @@ -5773,6 +5785,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 2" + " is not of any supported type." @@ -5789,6 +5805,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 2" + " is not of any supported type." @@ -5838,6 +5858,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 3", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 3" + " is not of any supported type." @@ -5853,6 +5877,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 4", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 4" + " is not of any supported type." @@ -8425,6 +8453,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -8456,6 +8488,10 @@ exports.install = (globalObject, globalNames) => { curArg = null; } else { if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arrayBufferViewOrURLMapConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (utils.isObject(curArg)) { if (!utils.isObject(curArg)) { throw new globalObject.TypeError( @@ -8521,6 +8557,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arrayBufferViewDupConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'arrayBufferViewDupConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -8595,10 +8635,16 @@ exports.install = (globalObject, globalNames) => { context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", globals: globalObject }); - } else if ( - ArrayBuffer.isView(V) && - (V.constructor.name === "Uint8Array" || V.constructor.name === "Uint16Array") - ) { + } else if (ArrayBuffer.isView(V) && V.constructor.name === "Uint8Array") { + V = conversions["Uint8Array"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); + } else if (ArrayBuffer.isView(V) && V.constructor.name === "Uint16Array") { + V = conversions["Uint16Array"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value" + @@ -12737,6 +12783,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'bs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." @@ -12812,6 +12862,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'abv' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'abv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." @@ -12928,6 +12982,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg) && curArg.constructor.name === "Uint8Array") { + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'u8aUnion' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); } else { curArg = conversions["DOMString"](curArg, { context: "Failed to execute 'u8aUnion' on 'BufferSourceTypes': parameter 1", @@ -17082,6 +17140,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 2" + " is not of any supported type." @@ -17098,6 +17160,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 2", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 2" + " is not of any supported type." @@ -17147,6 +17213,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 3", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 3" + " is not of any supported type." @@ -17162,6 +17232,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'incompatible3' on 'Overloads': parameter 4", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'incompatible3' on 'Overloads': parameter 4" + " is not of any supported type." @@ -19719,6 +19793,10 @@ exports.install = (globalObject, globalNames) => { globals: globalObject }); } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'bufferSourceOrURLConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -19750,6 +19828,10 @@ exports.install = (globalObject, globalNames) => { curArg = null; } else { if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arrayBufferViewOrURLMapConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else if (utils.isObject(curArg)) { if (!utils.isObject(curArg)) { throw new globalObject.TypeError( @@ -19815,6 +19897,10 @@ exports.install = (globalObject, globalNames) => { { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arrayBufferViewDupConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to execute 'arrayBufferViewDupConsumer' on 'TypedefsAndUnions': parameter 1" + @@ -19889,10 +19975,16 @@ exports.install = (globalObject, globalNames) => { context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", globals: globalObject }); - } else if ( - ArrayBuffer.isView(V) && - (V.constructor.name === "Uint8Array" || V.constructor.name === "Uint16Array") - ) { + } else if (ArrayBuffer.isView(V) && V.constructor.name === "Uint8Array") { + V = conversions["Uint8Array"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); + } else if (ArrayBuffer.isView(V) && V.constructor.name === "Uint16Array") { + V = conversions["Uint16Array"](V, { + context: "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value", + globals: globalObject + }); } else { throw new globalObject.TypeError( "Failed to set the 'buf' property on 'TypedefsAndUnions': The provided value" + From ae54c99e87892735cee778b0809ed88679612ffe Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:06:07 +0200 Subject: [PATCH 05/12] Test [AllowResizable] on ArrayBufferView types --- test/__snapshots__/test.js.snap | 198 ++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 3 + 2 files changed, 201 insertions(+) diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 91a78e48..82673600 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1600,6 +1600,44 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + arbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arbs(...args); + } + arab(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -1651,6 +1689,64 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].arsab(...args); } + + arabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arabv(...args); + } + + aru8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'aru8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'aru8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'aru8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].aru8a(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -1661,8 +1757,11 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + arbs: { enumerable: true }, arab: { enumerable: true }, arsab: { enumerable: true }, + arabv: { enumerable: true }, + aru8a: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; @@ -12997,6 +13096,44 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + arbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arbs(...args); + } + arab(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -13048,6 +13185,64 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].arsab(...args); } + + arabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arabv(...args); + } + + aru8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'aru8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'aru8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'aru8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + args.push(curArg); + } + return esValue[implSymbol].aru8a(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -13058,8 +13253,11 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + arbs: { enumerable: true }, arab: { enumerable: true }, arsab: { enumerable: true }, + arabv: { enumerable: true }, + aru8a: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index 82fb5ac6..a4f217ed 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -10,6 +10,9 @@ interface BufferSourceTypes { undefined sabUnion((SharedArrayBuffer or DOMString) ab); undefined u8aUnion((Uint8Array or DOMString) ab); + undefined arbs([AllowResizable] BufferSource source); undefined arab([AllowResizable] ArrayBuffer ab); undefined arsab([AllowResizable] SharedArrayBuffer sab); + undefined arabv([AllowResizable] ArrayBufferView abv); + undefined aru8a([AllowResizable] Uint8Array u8); }; From 36d3523b4f312c956ba96bc76355a0f7ff9a79e3 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:20:07 +0200 Subject: [PATCH 06/12] Support [AllowShared] on individual ArrayBufferView types --- lib/types.js | 4 +++ test/__snapshots__/test.js.snap | 54 +++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 2 ++ 3 files changed, 60 insertions(+) diff --git a/lib/types.js b/lib/types.js index 9621530c..eeb93dc8 100644 --- a/lib/types.js +++ b/lib/types.js @@ -436,6 +436,7 @@ function generateTypeConversion( const clamp = utils.getExtAttr(attrs, "Clamp"); const nullToEmptyString = utils.getExtAttr(attrs, "LegacyNullToEmptyString"); const allowResizable = utils.getExtAttr(attrs, "AllowResizable"); + const allowShared = utils.getExtAttr(extAttrs, "AllowShared"); let optString = `context: ${errPrefix}, globals: globalObject,`; if (clamp) { @@ -450,6 +451,9 @@ function generateTypeConversion( if (allowResizable) { optString += "allowResizable: true,"; } + if (allowShared) { + optString += "allowShared: true,"; + } if (idlType.array) { return ` for (let i = 0; i < ${name}.length; ++i) { diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 82673600..30ecb3e4 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1600,6 +1600,32 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + asu8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asu8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'asu8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + args.push(curArg); + } + return esValue[implSymbol].asu8a(...args); + } + arbs(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -1757,6 +1783,7 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + asu8a: { enumerable: true }, arbs: { enumerable: true }, arab: { enumerable: true }, arsab: { enumerable: true }, @@ -13096,6 +13123,32 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + asu8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asu8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'asu8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + args.push(curArg); + } + return esValue[implSymbol].asu8a(...args); + } + arbs(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -13253,6 +13306,7 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + asu8a: { enumerable: true }, arbs: { enumerable: true }, arab: { enumerable: true }, arsab: { enumerable: true }, diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index a4f217ed..ade208b2 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -10,6 +10,8 @@ interface BufferSourceTypes { undefined sabUnion((SharedArrayBuffer or DOMString) ab); undefined u8aUnion((Uint8Array or DOMString) ab); + undefined asu8a([AllowShared] Uint8Array u8); + undefined arbs([AllowResizable] BufferSource source); undefined arab([AllowResizable] ArrayBuffer ab); undefined arsab([AllowResizable] SharedArrayBuffer sab); From 96d497073cd2055bad58a4171f7616af426a2f6b Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:26:01 +0200 Subject: [PATCH 07/12] Support [AllowShared] on all ArrayBufferView types --- lib/context.js | 1 + lib/types.js | 17 +++- test/__snapshots__/test.js.snap | 152 ++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 2 + 4 files changed, 169 insertions(+), 3 deletions(-) diff --git a/lib/context.js b/lib/context.js index facd25ae..09a1004e 100644 --- a/lib/context.js +++ b/lib/context.js @@ -8,6 +8,7 @@ const builtinTypes = webidl.parse(` Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or Float32Array or Float64Array or DataView) ArrayBufferView; typedef (ArrayBufferView or ArrayBuffer) BufferSource; + typedef (ArrayBuffer or SharedArrayBuffer or [AllowShared] ArrayBufferView) AllowSharedBufferSource; typedef unsigned long long DOMTimeStamp; callback Function = any (any... arguments); diff --git a/lib/types.js b/lib/types.js index eeb93dc8..5e8ad026 100644 --- a/lib/types.js +++ b/lib/types.js @@ -36,6 +36,16 @@ function mergeExtAttrs(a = [], b = []) { return [...a, ...b]; } +function mergeExtAttrsOfTypes(idlTypes) { + const extAttrs = []; + for (const idlType of idlTypes) { + if (idlType.extAttrs !== undefined) { + extAttrs.push(...idlType.extAttrs); + } + } + return extAttrs; +} + // Types of types that generate an output file. const resolvedTypes = new Set(["callback", "callback interface", "dictionary", "enumeration", "interface"]); @@ -142,7 +152,7 @@ function generateTypeConversion( generateFrozenArray(); } else if (conversions[idlType.idlType]) { // string or number type compatible with webidl-conversions - str += generateWebIDLConversions(`conversions["${idlType.idlType}"]`); + str += generateWebIDLConversions(`conversions["${idlType.idlType}"]`, extAttrs); } else if (resolvedTypes.has(ctx.typeOf(idlType.idlType))) { // callback functions, callback interfaces, dictionaries, enumerations, and interfaces let fn; @@ -228,10 +238,11 @@ function generateTypeConversion( const viewIdlTypes = new Set([...union.ArrayBufferViews].map(item => item.idlType)); // Skip specific type check if all ArrayBufferView member types are allowed. if (viewIdlTypes.size === arrayBufferViewTypes.size) { + const viewExtAttrs = mergeExtAttrsOfTypes(union.ArrayBufferViews); // We can't call generateTypeConversion since that will just expand the union again and recurse back to here, // so instead we call generateWebIDLConversions directly. output.push(`if (ArrayBuffer.isView(${name})) { - ${generateWebIDLConversions(`conversions["ArrayBufferView"]`)} + ${generateWebIDLConversions(`conversions["ArrayBufferView"]`, viewExtAttrs)} }`); } else { for (const viewType of union.ArrayBufferViews) { @@ -436,7 +447,7 @@ function generateTypeConversion( const clamp = utils.getExtAttr(attrs, "Clamp"); const nullToEmptyString = utils.getExtAttr(attrs, "LegacyNullToEmptyString"); const allowResizable = utils.getExtAttr(attrs, "AllowResizable"); - const allowShared = utils.getExtAttr(extAttrs, "AllowShared"); + const allowShared = utils.getExtAttr(attrs, "AllowShared"); let optString = `context: ${errPrefix}, globals: globalObject,`; if (clamp) { diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 30ecb3e4..b07b1468 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1600,6 +1600,80 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + asbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].asbs(...args); + } + + asabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].asabv(...args); + } + asu8a(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -1783,6 +1857,8 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + asbs: { enumerable: true }, + asabv: { enumerable: true }, asu8a: { enumerable: true }, arbs: { enumerable: true }, arab: { enumerable: true }, @@ -13123,6 +13199,80 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].u8aUnion(...args); } + asbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'asbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].asbs(...args); + } + + asabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'asabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'asabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].asabv(...args); + } + asu8a(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -13306,6 +13456,8 @@ exports.install = (globalObject, globalNames) => { abUnion: { enumerable: true }, sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, + asbs: { enumerable: true }, + asabv: { enumerable: true }, asu8a: { enumerable: true }, arbs: { enumerable: true }, arab: { enumerable: true }, diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index ade208b2..1451c786 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -10,6 +10,8 @@ interface BufferSourceTypes { undefined sabUnion((SharedArrayBuffer or DOMString) ab); undefined u8aUnion((Uint8Array or DOMString) ab); + undefined asbs(AllowSharedBufferSource source); + undefined asabv([AllowShared] ArrayBufferView abv); undefined asu8a([AllowShared] Uint8Array u8); undefined arbs([AllowResizable] BufferSource source); From 7cdfaa8dd7f3565254dbf62d66c9fab0f1d85a3d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:28:01 +0200 Subject: [PATCH 08/12] Test [AllowResizable, AllowShared] --- test/__snapshots__/test.js.snap | 216 ++++++++++++++++++++++++++++ test/cases/BufferSourceTypes.webidl | 4 + 2 files changed, 220 insertions(+) diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index b07b1468..941ea500 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1847,6 +1847,111 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].aru8a(...args); } + + arsbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arsbs(...args); + } + + arsabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arsabv(...args); + } + + arsu8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsu8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'arsu8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + args.push(curArg); + } + return esValue[implSymbol].arsu8a(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -1865,6 +1970,9 @@ exports.install = (globalObject, globalNames) => { arsab: { enumerable: true }, arabv: { enumerable: true }, aru8a: { enumerable: true }, + arsbs: { enumerable: true }, + arsabv: { enumerable: true }, + arsu8a: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; @@ -13446,6 +13554,111 @@ exports.install = (globalObject, globalNames) => { } return esValue[implSymbol].aru8a(...args); } + + arsbs(source) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsbs' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isArrayBuffer(curArg)) { + curArg = conversions["ArrayBuffer"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (utils.isSharedArrayBuffer(curArg)) { + curArg = conversions["SharedArrayBuffer"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true + }); + } else if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arsbs(...args); + } + + arsabv(abv) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsabv' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (ArrayBuffer.isView(curArg)) { + curArg = conversions["ArrayBufferView"](curArg, { + context: "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + } else { + throw new globalObject.TypeError( + "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + ); + } + args.push(curArg); + } + return esValue[implSymbol].arsabv(...args); + } + + arsu8a(u8) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'arsu8a' called on an object that is not a valid instance of BufferSourceTypes." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'arsu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + curArg = conversions["Uint8Array"](curArg, { + context: "Failed to execute 'arsu8a' on 'BufferSourceTypes': parameter 1", + globals: globalObject, + allowResizable: true, + allowShared: true + }); + args.push(curArg); + } + return esValue[implSymbol].arsu8a(...args); + } } Object.defineProperties(BufferSourceTypes.prototype, { bs: { enumerable: true }, @@ -13464,6 +13677,9 @@ exports.install = (globalObject, globalNames) => { arsab: { enumerable: true }, arabv: { enumerable: true }, aru8a: { enumerable: true }, + arsbs: { enumerable: true }, + arsabv: { enumerable: true }, + arsu8a: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index 1451c786..03f165b0 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -19,4 +19,8 @@ interface BufferSourceTypes { undefined arsab([AllowResizable] SharedArrayBuffer sab); undefined arabv([AllowResizable] ArrayBufferView abv); undefined aru8a([AllowResizable] Uint8Array u8); + + undefined arsbs([AllowResizable] AllowSharedBufferSource source); + undefined arsabv([AllowResizable, AllowShared] ArrayBufferView abv); + undefined arsu8a([AllowResizable, AllowShared] Uint8Array u8); }; From 4a8e5dc970e8ad367495ba89a2f69895814ffaaf Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 01:44:30 +0200 Subject: [PATCH 09/12] Rename test operations for clarity --- test/__snapshots__/test.js.snap | 280 ++++++++++++++-------------- test/cases/BufferSourceTypes.webidl | 20 +- 2 files changed, 154 insertions(+), 146 deletions(-) diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 941ea500..c52c571d 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -1642,17 +1642,17 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].asbs(...args); } - asabv(abv) { + abvAllowShared(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'asabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'asabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -1660,57 +1660,57 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowShared' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].asabv(...args); + return esValue[implSymbol].abvAllowShared(...args); } - asu8a(u8) { + u8aAllowShared(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'asu8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'asu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'asu8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowShared: true }); args.push(curArg); } - return esValue[implSymbol].asu8a(...args); + return esValue[implSymbol].u8aAllowShared(...args); } - arbs(source) { + bsAllowResizable(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arbs' called on an object that is not a valid instance of BufferSourceTypes." + "'bsAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -1718,89 +1718,90 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arbs(...args); + return esValue[implSymbol].bsAllowResizable(...args); } - arab(ab) { + abAllowResizable(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arab' called on an object that is not a valid instance of BufferSourceTypes." + "'abAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arab' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].arab(...args); + return esValue[implSymbol].abAllowResizable(...args); } - arsab(sab) { + sabAllowResizable(sab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsab' called on an object that is not a valid instance of BufferSourceTypes." + "'sabAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'sabAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["SharedArrayBuffer"](curArg, { - context: "Failed to execute 'arsab' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'sabAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].arsab(...args); + return esValue[implSymbol].sabAllowResizable(...args); } - arabv(abv) { + abvAllowResizable(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -1808,57 +1809,58 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arabv(...args); + return esValue[implSymbol].abvAllowResizable(...args); } - aru8a(u8) { + u8aAllowResizable(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'aru8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'aru8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'aru8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].aru8a(...args); + return esValue[implSymbol].u8aAllowResizable(...args); } - arsbs(source) { + asbsAllowResizable(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsbs' called on an object that is not a valid instance of BufferSourceTypes." + "'asbsAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -1866,44 +1868,45 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (utils.isSharedArrayBuffer(curArg)) { curArg = conversions["SharedArrayBuffer"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arsbs(...args); + return esValue[implSymbol].asbsAllowResizable(...args); } - arsabv(abv) { + abvAllowResizableShared(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowResizableShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -1911,46 +1914,47 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arsabv(...args); + return esValue[implSymbol].abvAllowResizableShared(...args); } - arsu8a(u8) { + u8aAllowResizableShared(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsu8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowResizableShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowResizableShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'arsu8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowResizableShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); args.push(curArg); } - return esValue[implSymbol].arsu8a(...args); + return esValue[implSymbol].u8aAllowResizableShared(...args); } } Object.defineProperties(BufferSourceTypes.prototype, { @@ -1963,16 +1967,16 @@ exports.install = (globalObject, globalNames) => { sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, asbs: { enumerable: true }, - asabv: { enumerable: true }, - asu8a: { enumerable: true }, - arbs: { enumerable: true }, - arab: { enumerable: true }, - arsab: { enumerable: true }, - arabv: { enumerable: true }, - aru8a: { enumerable: true }, - arsbs: { enumerable: true }, - arsabv: { enumerable: true }, - arsu8a: { enumerable: true }, + abvAllowShared: { enumerable: true }, + u8aAllowShared: { enumerable: true }, + bsAllowResizable: { enumerable: true }, + abAllowResizable: { enumerable: true }, + sabAllowResizable: { enumerable: true }, + abvAllowResizable: { enumerable: true }, + u8aAllowResizable: { enumerable: true }, + asbsAllowResizable: { enumerable: true }, + abvAllowResizableShared: { enumerable: true }, + u8aAllowResizableShared: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; @@ -13349,17 +13353,17 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].asbs(...args); } - asabv(abv) { + abvAllowShared(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'asabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'asabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -13367,57 +13371,57 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'asabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowShared' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].asabv(...args); + return esValue[implSymbol].abvAllowShared(...args); } - asu8a(u8) { + u8aAllowShared(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'asu8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'asu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'asu8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowShared: true }); args.push(curArg); } - return esValue[implSymbol].asu8a(...args); + return esValue[implSymbol].u8aAllowShared(...args); } - arbs(source) { + bsAllowResizable(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arbs' called on an object that is not a valid instance of BufferSourceTypes." + "'bsAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -13425,89 +13429,90 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'bsAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arbs(...args); + return esValue[implSymbol].bsAllowResizable(...args); } - arab(ab) { + abAllowResizable(ab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arab' called on an object that is not a valid instance of BufferSourceTypes." + "'abAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arab' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].arab(...args); + return esValue[implSymbol].abAllowResizable(...args); } - arsab(sab) { + sabAllowResizable(sab) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsab' called on an object that is not a valid instance of BufferSourceTypes." + "'sabAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsab' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'sabAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["SharedArrayBuffer"](curArg, { - context: "Failed to execute 'arsab' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'sabAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].arsab(...args); + return esValue[implSymbol].sabAllowResizable(...args); } - arabv(abv) { + abvAllowResizable(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -13515,57 +13520,58 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arabv(...args); + return esValue[implSymbol].abvAllowResizable(...args); } - aru8a(u8) { + u8aAllowResizable(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'aru8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'aru8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'aru8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); args.push(curArg); } - return esValue[implSymbol].aru8a(...args); + return esValue[implSymbol].u8aAllowResizable(...args); } - arsbs(source) { + asbsAllowResizable(source) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsbs' called on an object that is not a valid instance of BufferSourceTypes." + "'asbsAllowResizable' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsbs' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -13573,44 +13579,45 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (utils.isArrayBuffer(curArg)) { curArg = conversions["ArrayBuffer"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (utils.isSharedArrayBuffer(curArg)) { curArg = conversions["SharedArrayBuffer"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true }); } else if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arsbs' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'asbsAllowResizable' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arsbs(...args); + return esValue[implSymbol].asbsAllowResizable(...args); } - arsabv(abv) { + abvAllowResizableShared(abv) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsabv' called on an object that is not a valid instance of BufferSourceTypes." + "'abvAllowResizableShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsabv' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; @@ -13618,46 +13625,47 @@ exports.install = (globalObject, globalNames) => { let curArg = arguments[0]; if (ArrayBuffer.isView(curArg)) { curArg = conversions["ArrayBufferView"](curArg, { - context: "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); } else { throw new globalObject.TypeError( - "Failed to execute 'arsabv' on 'BufferSourceTypes': parameter 1" + " is not of any supported type." + "Failed to execute 'abvAllowResizableShared' on 'BufferSourceTypes': parameter 1" + + " is not of any supported type." ); } args.push(curArg); } - return esValue[implSymbol].arsabv(...args); + return esValue[implSymbol].abvAllowResizableShared(...args); } - arsu8a(u8) { + u8aAllowResizableShared(u8) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { throw new globalObject.TypeError( - "'arsu8a' called on an object that is not a valid instance of BufferSourceTypes." + "'u8aAllowResizableShared' called on an object that is not a valid instance of BufferSourceTypes." ); } if (arguments.length < 1) { throw new globalObject.TypeError( - \`Failed to execute 'arsu8a' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` + \`Failed to execute 'u8aAllowResizableShared' on 'BufferSourceTypes': 1 argument required, but only \${arguments.length} present.\` ); } const args = []; { let curArg = arguments[0]; curArg = conversions["Uint8Array"](curArg, { - context: "Failed to execute 'arsu8a' on 'BufferSourceTypes': parameter 1", + context: "Failed to execute 'u8aAllowResizableShared' on 'BufferSourceTypes': parameter 1", globals: globalObject, allowResizable: true, allowShared: true }); args.push(curArg); } - return esValue[implSymbol].arsu8a(...args); + return esValue[implSymbol].u8aAllowResizableShared(...args); } } Object.defineProperties(BufferSourceTypes.prototype, { @@ -13670,16 +13678,16 @@ exports.install = (globalObject, globalNames) => { sabUnion: { enumerable: true }, u8aUnion: { enumerable: true }, asbs: { enumerable: true }, - asabv: { enumerable: true }, - asu8a: { enumerable: true }, - arbs: { enumerable: true }, - arab: { enumerable: true }, - arsab: { enumerable: true }, - arabv: { enumerable: true }, - aru8a: { enumerable: true }, - arsbs: { enumerable: true }, - arsabv: { enumerable: true }, - arsu8a: { enumerable: true }, + abvAllowShared: { enumerable: true }, + u8aAllowShared: { enumerable: true }, + bsAllowResizable: { enumerable: true }, + abAllowResizable: { enumerable: true }, + sabAllowResizable: { enumerable: true }, + abvAllowResizable: { enumerable: true }, + u8aAllowResizable: { enumerable: true }, + asbsAllowResizable: { enumerable: true }, + abvAllowResizableShared: { enumerable: true }, + u8aAllowResizableShared: { enumerable: true }, [Symbol.toStringTag]: { value: "BufferSourceTypes", configurable: true } }); ctorRegistry[interfaceName] = BufferSourceTypes; diff --git a/test/cases/BufferSourceTypes.webidl b/test/cases/BufferSourceTypes.webidl index 03f165b0..6651551e 100644 --- a/test/cases/BufferSourceTypes.webidl +++ b/test/cases/BufferSourceTypes.webidl @@ -11,16 +11,16 @@ interface BufferSourceTypes { undefined u8aUnion((Uint8Array or DOMString) ab); undefined asbs(AllowSharedBufferSource source); - undefined asabv([AllowShared] ArrayBufferView abv); - undefined asu8a([AllowShared] Uint8Array u8); + undefined abvAllowShared([AllowShared] ArrayBufferView abv); + undefined u8aAllowShared([AllowShared] Uint8Array u8); - undefined arbs([AllowResizable] BufferSource source); - undefined arab([AllowResizable] ArrayBuffer ab); - undefined arsab([AllowResizable] SharedArrayBuffer sab); - undefined arabv([AllowResizable] ArrayBufferView abv); - undefined aru8a([AllowResizable] Uint8Array u8); + undefined bsAllowResizable([AllowResizable] BufferSource source); + undefined abAllowResizable([AllowResizable] ArrayBuffer ab); + undefined sabAllowResizable([AllowResizable] SharedArrayBuffer sab); + undefined abvAllowResizable([AllowResizable] ArrayBufferView abv); + undefined u8aAllowResizable([AllowResizable] Uint8Array u8); - undefined arsbs([AllowResizable] AllowSharedBufferSource source); - undefined arsabv([AllowResizable, AllowShared] ArrayBufferView abv); - undefined arsu8a([AllowResizable, AllowShared] Uint8Array u8); + undefined asbsAllowResizable([AllowResizable] AllowSharedBufferSource source); + undefined abvAllowResizableShared([AllowResizable, AllowShared] ArrayBufferView abv); + undefined u8aAllowResizableShared([AllowResizable, AllowShared] Uint8Array u8); }; From 173441c611048afb6e72f7e5d0f8d8f888ca9d35 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 23:37:13 +0200 Subject: [PATCH 10/12] Optimize sameType helper --- lib/types.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/types.js b/lib/types.js index 5e8ad026..b33dc827 100644 --- a/lib/types.js +++ b/lib/types.js @@ -704,20 +704,26 @@ function sameType(ctx, type1, type2) { sameType(ctx, extracted1.record, extracted2.record) && sameType(ctx, extracted1.ArrayBuffer, extracted2.ArrayBuffer) && sameType(ctx, extracted1.SharedArrayBuffer, extracted2.SharedArrayBuffer) && - JSON.stringify([...extracted1.ArrayBufferViews].sort()) === - JSON.stringify([...extracted2.ArrayBufferViews].sort()) && + sameTypeArray(ctx, [...extracted1.ArrayBufferViews].sort(), [...extracted2.ArrayBufferViews].sort()) && extracted1.object === extracted2.object && sameType(ctx, extracted1.string, extracted2.string) && sameType(ctx, extracted1.numeric, extracted2.numeric) && sameType(ctx, extracted1.boolean, extracted2.boolean) && extracted1.callback === extracted2.callback && sameType(ctx, extracted1.dictionary, extracted2.dictionary) && - JSON.stringify([...extracted1.interfaces].sort()) === - JSON.stringify([...extracted2.interfaces].sort()) && + sameArray([...extracted1.interfaces].sort(), [...extracted2.interfaces].sort()) && extracted1.callbackInterface === extracted2.callbackInterface && extracted1.unknown === extracted2.unknown; } +function sameTypeArray(ctx, types1, types2) { + return sameArray(types1, types2, (type1, type2) => sameType(ctx, type1, type2)); +} + +function sameArray(array1, array2, comparator = (x, y) => x === y) { + return array1.length === array2.length && array1.every((element1, index) => comparator(element1, array2[index])); +} + function areDistinguishable(ctx, type1, type2) { const resolved1 = resolveType(ctx, type1); const resolved2 = resolveType(ctx, type2); From ff48336af09c8a69005268bc33f3e54aaf792f90 Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Sun, 28 Sep 2025 14:19:19 +0200 Subject: [PATCH 11/12] Fix unions with callback functions and callback interfaces --- lib/types.js | 7 +- test/__snapshots__/test.js.snap | 160 ++++++++++++++++++++++++++++ test/cases/TypedefsAndUnions.webidl | 2 + 3 files changed, 166 insertions(+), 3 deletions(-) diff --git a/lib/types.js b/lib/types.js index b33dc827..7c224262 100644 --- a/lib/types.js +++ b/lib/types.js @@ -594,7 +594,7 @@ function extractUnionInfo(ctx, idlType, errPrefix) { if (seen.dictionaryLike) { error("Callback functions are not distinguishable with dictionary-like types"); } - seen.callbackFunction = item.idlType; + seen.callbackFunction = item; } else if (ctx.dictionaries.has(item.idlType)) { if (seen.object) { error("Dictionary-like types are not distinguishable with object type"); @@ -616,7 +616,7 @@ function extractUnionInfo(ctx, idlType, errPrefix) { if (seen.dictionaryLike) { error("There can only be one dictionary-like type in a union type"); } - seen.callbackInterface = item.idlType; + seen.callbackInterface = item; } else if (ctx.interfaces.has(item.idlType)) { if (seen.object) { error("Interface types are not distinguishable with object type"); @@ -710,9 +710,10 @@ function sameType(ctx, type1, type2) { sameType(ctx, extracted1.numeric, extracted2.numeric) && sameType(ctx, extracted1.boolean, extracted2.boolean) && extracted1.callback === extracted2.callback && + sameType(ctx, extracted1.callbackFunction, extracted2.callbackFunction) && sameType(ctx, extracted1.dictionary, extracted2.dictionary) && sameArray([...extracted1.interfaces].sort(), [...extracted2.interfaces].sort()) && - extracted1.callbackInterface === extracted2.callbackInterface && + sameType(ctx, extracted1.callbackInterface, extracted2.callbackInterface) && extracted1.unknown === extracted2.unknown; } diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index c52c571d..7f1bfc0f 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -8407,6 +8407,8 @@ const utils = require("./utils.js"); const RequestDestination = require("./RequestDestination.js"); const URL = require("./URL.js"); +const AsyncCallbackFunction = require("./AsyncCallbackFunction.js"); +const AsyncCallbackInterface = require("./AsyncCallbackInterface.js"); const implSymbol = utils.implSymbol; const ctorRegistrySymbol = utils.ctorRegistrySymbol; @@ -8923,6 +8925,82 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].arrayBufferOrSharedArrayBufferConsumer(...args); } + callbackFunctionOrNumConsumer(cb) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'callbackFunctionOrNumConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (typeof curArg === "function") { + curArg = AsyncCallbackFunction.convert(globalObject, curArg, { + context: + "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1" + + " callback function" + }); + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].callbackFunctionOrNumConsumer(...args); + } + + callbackInterfaceOrNumConsumer(cb) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'callbackInterfaceOrNumConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isObject(curArg)) { + curArg = AsyncCallbackInterface.convert(globalObject, curArg, { + context: + "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1" + + " callback interface" + }); + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].callbackInterfaceOrNumConsumer(...args); + } + get buf() { const esValue = this !== null && this !== undefined ? this : globalObject; @@ -9008,6 +9086,8 @@ exports.install = (globalObject, globalNames) => { arrayBufferViewOrURLMapConsumer: { enumerable: true }, arrayBufferViewDupConsumer: { enumerable: true }, arrayBufferOrSharedArrayBufferConsumer: { enumerable: true }, + callbackFunctionOrNumConsumer: { enumerable: true }, + callbackInterfaceOrNumConsumer: { enumerable: true }, buf: { enumerable: true }, time: { enumerable: true }, [Symbol.toStringTag]: { value: "TypedefsAndUnions", configurable: true } @@ -20061,6 +20141,8 @@ const utils = require("./utils.js"); const RequestDestination = require("./RequestDestination.js"); const URL = require("./URL.js"); +const AsyncCallbackFunction = require("./AsyncCallbackFunction.js"); +const AsyncCallbackInterface = require("./AsyncCallbackInterface.js"); const implSymbol = utils.implSymbol; const ctorRegistrySymbol = utils.ctorRegistrySymbol; @@ -20577,6 +20659,82 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].arrayBufferOrSharedArrayBufferConsumer(...args); } + callbackFunctionOrNumConsumer(cb) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'callbackFunctionOrNumConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (typeof curArg === "function") { + curArg = AsyncCallbackFunction.convert(globalObject, curArg, { + context: + "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1" + + " callback function" + }); + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackFunctionOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].callbackFunctionOrNumConsumer(...args); + } + + callbackInterfaceOrNumConsumer(cb) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'callbackInterfaceOrNumConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isObject(curArg)) { + curArg = AsyncCallbackInterface.convert(globalObject, curArg, { + context: + "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1" + + " callback interface" + }); + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'callbackInterfaceOrNumConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].callbackInterfaceOrNumConsumer(...args); + } + get buf() { const esValue = this !== null && this !== undefined ? this : globalObject; @@ -20662,6 +20820,8 @@ exports.install = (globalObject, globalNames) => { arrayBufferViewOrURLMapConsumer: { enumerable: true }, arrayBufferViewDupConsumer: { enumerable: true }, arrayBufferOrSharedArrayBufferConsumer: { enumerable: true }, + callbackFunctionOrNumConsumer: { enumerable: true }, + callbackInterfaceOrNumConsumer: { enumerable: true }, buf: { enumerable: true }, time: { enumerable: true }, [Symbol.toStringTag]: { value: "TypedefsAndUnions", configurable: true } diff --git a/test/cases/TypedefsAndUnions.webidl b/test/cases/TypedefsAndUnions.webidl index 0e9edea9..0827aa6a 100644 --- a/test/cases/TypedefsAndUnions.webidl +++ b/test/cases/TypedefsAndUnions.webidl @@ -10,6 +10,8 @@ interface TypedefsAndUnions { undefined arrayBufferViewOrURLMapConsumer((ArrayBufferView or URLMap) b); undefined arrayBufferViewDupConsumer((ArrayBufferView or Uint8ClampedArray) b); undefined arrayBufferOrSharedArrayBufferConsumer((ArrayBuffer or SharedArrayBuffer) b); + undefined callbackFunctionOrNumConsumer((AsyncCallbackFunction or double) cb); + undefined callbackInterfaceOrNumConsumer((AsyncCallbackInterface or double) cb); attribute (ArrayBuffer or Uint8Array or Uint16Array) buf; attribute DOMTimeStamp time; From 47447ef703b50a0ffa9a9e4c1f7c5bc7845f205d Mon Sep 17 00:00:00 2001 From: Mattias Buelens Date: Thu, 25 Sep 2025 02:02:04 +0200 Subject: [PATCH 12/12] Simplify generated code for `object` type in unions This also fixes the crash reported in #231. --- lib/types.js | 56 ++++++++++------------ test/__snapshots__/test.js.snap | 74 +++++++++++++++++++++++++++++ test/cases/TypedefsAndUnions.webidl | 1 + 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/lib/types.js b/lib/types.js index 7c224262..f90b5edb 100644 --- a/lib/types.js +++ b/lib/types.js @@ -202,9 +202,13 @@ function generateTypeConversion( } if (union.object) { - output.push(`if (utils.isObject(${name}) && ${name}[utils.implSymbol]) { - ${name} = utils.implForWrapper(${name}); - }`); + output.push(` + if (utils.isObject(${name})) { + if (${name}[utils.implSymbol]) { + ${name} = utils.implForWrapper(${name}); + } + } + `); } else if (union.interfaces.size > 0) { const exprs = [...union.interfaces].map(iface => { let fn; @@ -224,17 +228,17 @@ function generateTypeConversion( `); } - if (union.ArrayBuffer || union.object) { + if (union.ArrayBuffer) { output.push(`if (utils.isArrayBuffer(${name})) { ${generateTypeConversion(ctx, name, union.ArrayBuffer, [], parentName, errPrefix).body} }`); } - if (union.SharedArrayBuffer || union.object) { + if (union.SharedArrayBuffer) { output.push(`if (utils.isSharedArrayBuffer(${name})) { ${generateTypeConversion(ctx, name, union.SharedArrayBuffer, [], parentName, errPrefix).body} }`); } - if (union.ArrayBufferViews.size > 0 || union.object) { + if (union.ArrayBufferViews.size > 0) { const viewIdlTypes = new Set([...union.ArrayBufferViews].map(item => item.idlType)); // Skip specific type check if all ArrayBufferView member types are allowed. if (viewIdlTypes.size === arrayBufferViewTypes.size) { @@ -253,30 +257,24 @@ function generateTypeConversion( } } - if (union.callbackFunction || union.object) { - let code = `if (typeof ${name} === "function") {`; - - if (union.callbackFunction) { - const conv = generateTypeConversion( - ctx, - name, - union.callbackFunction, - [], - parentName, - `${errPrefix} + " callback function"` - ); - requires.merge(conv.requires); - code += conv.body; - } else if (union.object) { - // noop - } - - code += "}"; - - output.push(code); + if (union.callbackFunction) { + const conv = generateTypeConversion( + ctx, + name, + union.callbackFunction, + [], + parentName, + `${errPrefix} + " callback function"` + ); + requires.merge(conv.requires); + output.push(` + if (typeof ${name} === "function") { + ${conv.body} + } + `); } - if (union.sequenceLike || union.dictionary || union.record || union.object || union.callbackInterface) { + if (union.sequenceLike || union.dictionary || union.record || union.callbackInterface) { let code = `if (utils.isObject(${name})) {`; if (union.sequenceLike) { @@ -320,8 +318,6 @@ function generateTypeConversion( ); requires.merge(conv.requires); code += conv.body; - } else if (union.object) { - // noop } if (union.sequenceLike) { diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index 7f1bfc0f..4362fead 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -8645,6 +8645,42 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].numOrStrOrURLOrNullConsumer(...args); } + numOrObjConsumer(a) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'numOrObjConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isObject(curArg)) { + if (curArg[utils.implSymbol]) { + curArg = utils.implForWrapper(curArg); + } + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].numOrObjConsumer(...args); + } + urlMapInnerConsumer(a) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -9080,6 +9116,7 @@ exports.install = (globalObject, globalNames) => { numOrEnumConsumer: { enumerable: true }, numOrStrOrNullConsumer: { enumerable: true }, numOrStrOrURLOrNullConsumer: { enumerable: true }, + numOrObjConsumer: { enumerable: true }, urlMapInnerConsumer: { enumerable: true }, urlMapConsumer: { enumerable: true }, bufferSourceOrURLConsumer: { enumerable: true }, @@ -20379,6 +20416,42 @@ exports.install = (globalObject, globalNames) => { return esValue[implSymbol].numOrStrOrURLOrNullConsumer(...args); } + numOrObjConsumer(a) { + const esValue = this !== null && this !== undefined ? this : globalObject; + if (!exports.is(esValue)) { + throw new globalObject.TypeError( + "'numOrObjConsumer' called on an object that is not a valid instance of TypedefsAndUnions." + ); + } + + if (arguments.length < 1) { + throw new globalObject.TypeError( + \`Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': 1 argument required, but only \${arguments.length} present.\` + ); + } + const args = []; + { + let curArg = arguments[0]; + if (utils.isObject(curArg)) { + if (curArg[utils.implSymbol]) { + curArg = utils.implForWrapper(curArg); + } + } else if (typeof curArg === "number") { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } else { + curArg = conversions["double"](curArg, { + context: "Failed to execute 'numOrObjConsumer' on 'TypedefsAndUnions': parameter 1", + globals: globalObject + }); + } + args.push(curArg); + } + return esValue[implSymbol].numOrObjConsumer(...args); + } + urlMapInnerConsumer(a) { const esValue = this !== null && this !== undefined ? this : globalObject; if (!exports.is(esValue)) { @@ -20814,6 +20887,7 @@ exports.install = (globalObject, globalNames) => { numOrEnumConsumer: { enumerable: true }, numOrStrOrNullConsumer: { enumerable: true }, numOrStrOrURLOrNullConsumer: { enumerable: true }, + numOrObjConsumer: { enumerable: true }, urlMapInnerConsumer: { enumerable: true }, urlMapConsumer: { enumerable: true }, bufferSourceOrURLConsumer: { enumerable: true }, diff --git a/test/cases/TypedefsAndUnions.webidl b/test/cases/TypedefsAndUnions.webidl index 0827aa6a..7e08630d 100644 --- a/test/cases/TypedefsAndUnions.webidl +++ b/test/cases/TypedefsAndUnions.webidl @@ -4,6 +4,7 @@ interface TypedefsAndUnions { undefined numOrEnumConsumer((double or RequestDestination)? a); undefined numOrStrOrNullConsumer(NumOrStrOrNull a); undefined numOrStrOrURLOrNullConsumer(NumOrStrOrURLOrNull? a); + undefined numOrObjConsumer((double or object) a); undefined urlMapInnerConsumer(URLMapInner a); undefined urlMapConsumer(URLMap a); undefined bufferSourceOrURLConsumer((BufferSource or URL) b);