Skip to content

Commit fc78ced

Browse files
jazellyjakecastelli
authored andcommitted
lib: convert signals to array before validation
Co-authored-by: Jake Yuesong Li <[email protected]> PR-URL: #54714 Fixes: #54674 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Matthew Aitken <[email protected]> Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 1fb67af commit fc78ced

File tree

4 files changed

+107
-38
lines changed

4 files changed

+107
-38
lines changed

lib/internal/abort_controller.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const {
3939
ERR_INVALID_THIS,
4040
},
4141
} = require('internal/errors');
42+
const {
43+
converters,
44+
createSequenceConverter,
45+
} = require('internal/webidl');
4246

4347
const {
4448
validateAbortSignal,
@@ -225,15 +229,19 @@ class AbortSignal extends EventTarget {
225229
* @returns {AbortSignal}
226230
*/
227231
static any(signals) {
228-
validateAbortSignalArray(signals, 'signals');
232+
const signalsArray = createSequenceConverter(
233+
converters.any,
234+
)(signals);
235+
236+
validateAbortSignalArray(signalsArray, 'signals');
229237
const resultSignal = new AbortSignal(kDontThrowSymbol, { composite: true });
230-
if (!signals.length) {
238+
if (!signalsArray.length) {
231239
return resultSignal;
232240
}
233241
const resultSignalWeakRef = new WeakRef(resultSignal);
234242
resultSignal[kSourceSignals] = new SafeSet();
235-
for (let i = 0; i < signals.length; i++) {
236-
const signal = signals[i];
243+
for (let i = 0; i < signalsArray.length; i++) {
244+
const signal = signalsArray[i];
237245
if (signal.aborted) {
238246
abortSignal(resultSignal, signal.reason);
239247
return resultSignal;

lib/internal/crypto/webidl.js

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ const {
2222
ObjectPrototypeIsPrototypeOf,
2323
SafeArrayIterator,
2424
String,
25-
SymbolIterator,
2625
TypedArrayPrototypeGetBuffer,
2726
TypedArrayPrototypeGetSymbolToStringTag,
2827
globalThis: {
@@ -33,6 +32,7 @@ const {
3332
const {
3433
makeException,
3534
createEnumConverter,
35+
createSequenceConverter,
3636
} = require('internal/webidl');
3737

3838
const {
@@ -293,39 +293,6 @@ function createDictionaryConverter(name, dictionaries) {
293293
};
294294
}
295295

296-
function createSequenceConverter(converter) {
297-
return function(V, opts = kEmptyObject) {
298-
if (type(V) !== 'Object') {
299-
throw makeException(
300-
'can not be converted to sequence.',
301-
opts);
302-
}
303-
const iter = V?.[SymbolIterator]?.();
304-
if (iter === undefined) {
305-
throw makeException(
306-
'can not be converted to sequence.',
307-
opts);
308-
}
309-
const array = [];
310-
while (true) {
311-
const res = iter?.next?.();
312-
if (res === undefined) {
313-
throw makeException(
314-
'can not be converted to sequence.',
315-
opts);
316-
}
317-
if (res.done === true) break;
318-
const val = converter(res.value, {
319-
__proto__: null,
320-
...opts,
321-
context: `${opts.context}, index ${array.length}`,
322-
});
323-
ArrayPrototypePush(array, val);
324-
}
325-
return array;
326-
};
327-
}
328-
329296
function createInterfaceConverter(name, prototype) {
330297
return (V, opts) => {
331298
if (!ObjectPrototypeIsPrototypeOf(prototype, V)) {

lib/internal/webidl.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const {
4+
ArrayPrototypePush,
45
MathAbs,
56
MathMax,
67
MathMin,
@@ -13,6 +14,7 @@ const {
1314
ObjectAssign,
1415
SafeSet,
1516
String,
17+
SymbolIterator,
1618
TypeError,
1719
} = primordials;
1820

@@ -25,6 +27,15 @@ const { kEmptyObject } = require('internal/util');
2527

2628
const converters = { __proto__: null };
2729

30+
/**
31+
* @see https://webidl.spec.whatwg.org/#es-any
32+
* @param {any} V
33+
* @returns {any}
34+
*/
35+
converters.any = (V) => {
36+
return V;
37+
};
38+
2839
// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart
2940
const integerPart = MathTrunc;
3041

@@ -209,10 +220,76 @@ function createEnumConverter(name, values) {
209220
};
210221
}
211222

223+
// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
224+
function type(V) {
225+
if (V === null)
226+
return 'Null';
227+
228+
switch (typeof V) {
229+
case 'undefined':
230+
return 'Undefined';
231+
case 'boolean':
232+
return 'Boolean';
233+
case 'number':
234+
return 'Number';
235+
case 'string':
236+
return 'String';
237+
case 'symbol':
238+
return 'Symbol';
239+
case 'bigint':
240+
return 'BigInt';
241+
case 'object': // Fall through
242+
case 'function': // Fall through
243+
default:
244+
// Per ES spec, typeof returns an implemention-defined value that is not
245+
// any of the existing ones for uncallable non-standard exotic objects.
246+
// Yet Type() which the Web IDL spec depends on returns Object for such
247+
// cases. So treat the default case as an object.
248+
return 'Object';
249+
}
250+
}
251+
252+
// https://webidl.spec.whatwg.org/#es-sequence
253+
function createSequenceConverter(converter) {
254+
return function(V, opts = kEmptyObject) {
255+
if (type(V) !== 'Object') {
256+
throw makeException(
257+
'can not be converted to sequence.',
258+
opts);
259+
}
260+
const iter = V?.[SymbolIterator]?.();
261+
if (iter === undefined) {
262+
throw makeException(
263+
'can not be converted to sequence.',
264+
opts);
265+
}
266+
const array = [];
267+
while (true) {
268+
const res = iter?.next?.();
269+
if (res === undefined) {
270+
throw makeException(
271+
'can not be converted to sequence.',
272+
opts);
273+
}
274+
if (res.done === true) break;
275+
const val = converter(res.value, {
276+
__proto__: null,
277+
...opts,
278+
context: `${opts.context}, index ${array.length}`,
279+
});
280+
ArrayPrototypePush(array, val);
281+
};
282+
return array;
283+
};
284+
}
285+
286+
212287
module.exports = {
288+
type,
213289
converters,
214290
convertToInt,
215291
createEnumConverter,
292+
createSequenceConverter,
216293
evenRound,
217294
makeException,
218295
};

test/parallel/test-abortsignal-any.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,21 @@ describe('AbortSignal.any()', { concurrency: !process.env.TEST_PARALLEL }, () =>
101101
controller.abort();
102102
assert.strictEqual(result, '01234');
103103
});
104+
105+
it('must accept WebIDL sequence', () => {
106+
const controller = new AbortController();
107+
const iterable = {
108+
*[Symbol.iterator]() {
109+
yield controller.signal;
110+
yield new AbortController().signal;
111+
yield new AbortController().signal;
112+
yield new AbortController().signal;
113+
},
114+
};
115+
const signal = AbortSignal.any(iterable);
116+
let result = 0;
117+
signal.addEventListener('abort', () => result += 1);
118+
controller.abort();
119+
assert.strictEqual(result, 1);
120+
});
104121
});

0 commit comments

Comments
 (0)