Skip to content

Commit d1965f9

Browse files
jazellyaduh95
authored andcommitted
lib: implement webidl dictionary converter and use it in structuredClone
This commit provides a factory to generate `dictionaryConverter` compliant with the spec. The implemented factory function is used for the `structuredClone` algorithm with updated test cases. PR-URL: #55489 Reviewed-By: Matthew Aitken <maitken033380023@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent bf552fa commit d1965f9

3 files changed

Lines changed: 98 additions & 23 deletions

File tree

‎lib/internal/webidl.js‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const{
44
ArrayPrototypePush,
5+
ArrayPrototypeToSorted,
56
MathAbs,
67
MathMax,
78
MathMin,
@@ -272,6 +273,67 @@ function type(V) {
272273
}
273274
}
274275

276+
// https://webidl.spec.whatwg.org/#js-dictionary
277+
functioncreateDictionaryConverter(members){
278+
// The spec requires us to operate the members of a dictionary in
279+
// lexicographical order. We are doing this in the outer scope to
280+
// reduce the overhead that could happen in the returned function.
281+
constsortedMembers=ArrayPrototypeToSorted(members,(a,b)=>{
282+
if(a.key===b.key){
283+
return0;
284+
}
285+
returna.key<b.key ? -1 : 1;
286+
});
287+
288+
returnfunction(
289+
V,
290+
opts=kEmptyObject,
291+
){
292+
if(V!=null&&type(V)!==OBJECT){
293+
throwmakeException(
294+
'cannot be converted to a dictionary',
295+
opts,
296+
);
297+
}
298+
299+
constidlDict={__proto__: null};
300+
for(leti=0;i<sortedMembers.length;i++){
301+
constmember=sortedMembers[i];
302+
constkey=member.key;
303+
letjsMemberValue;
304+
if(V==null){
305+
jsMemberValue=undefined;
306+
}else{
307+
jsMemberValue=V[key];
308+
}
309+
310+
if(jsMemberValue!==undefined){
311+
constmemberContext=opts.context ? `${key} in ${opts.context}` : `${key}`;
312+
constconverter=member.converter;
313+
constidlMemberValue=converter(
314+
jsMemberValue,
315+
{
316+
__proto__: null,
317+
prefix: opts.prefix,
318+
context: memberContext,
319+
},
320+
);
321+
idlDict[key]=idlMemberValue;
322+
}elseif(typeofmember.defaultValue==='function'){
323+
constidlMemberValue=member.defaultValue();
324+
idlDict[key]=idlMemberValue;
325+
}elseif(member.required){
326+
throwmakeException(
327+
`cannot be converted because of the missing '${key}'`,
328+
opts,
329+
);
330+
}
331+
}
332+
333+
returnidlDict;
334+
};
335+
}
336+
275337
// https://webidl.spec.whatwg.org/#es-sequence
276338
functioncreateSequenceConverter(converter){
277339
returnfunction(V,opts=kEmptyObject){
@@ -327,6 +389,7 @@ module.exports = {
327389
createEnumConverter,
328390
createInterfaceConverter,
329391
createSequenceConverter,
392+
createDictionaryConverter,
330393
evenRound,
331394
makeException,
332395
};

‎lib/internal/worker/js_transferable.js‎

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const {
55
}=primordials;
66
const{
77
codes: {
8-
ERR_INVALID_ARG_TYPE,
98
ERR_MISSING_ARGS,
109
},
1110
}=require('internal/errors');
@@ -98,29 +97,31 @@ function markTransferMode(obj, cloneable = false, transferable = false) {
9897
obj[transfer_mode_private_symbol]=mode;
9998
}
10099

100+
101+
webidl.converters.StructuredSerializeOptions=webidl
102+
.createDictionaryConverter(
103+
[
104+
{
105+
key: 'transfer',
106+
converter: webidl.converters['sequence<object>'],
107+
defaultValue: ()=>[],
108+
},
109+
],
110+
);
111+
101112
functionstructuredClone(value,options){
102113
if(arguments.length===0){
103114
thrownewERR_MISSING_ARGS('The value argument must be specified');
104115
}
105116

106-
// TODO(jazelly): implement generic webidl dictionary converter
107-
constprefix='Options';
108-
constoptionsType=webidl.type(options);
109-
if(optionsType!=='Undefined'&&optionsType!=='Null'&&optionsType!=='Object'){
110-
thrownewERR_INVALID_ARG_TYPE(
111-
prefix,
112-
['object','null','undefined'],
113-
options,
114-
);
115-
}
116-
constkey='transfer';
117-
constidlOptions={__proto__: null,[key]: []};
118-
if(options!=null&&keyinoptions&&options[key]!==undefined){
119-
idlOptions[key]=webidl.converters['sequence<object>'](options[key],{
117+
constidlOptions=webidl.converters.StructuredSerializeOptions(
118+
options,
119+
{
120120
__proto__: null,
121-
context: 'Transfer',
122-
});
123-
}
121+
prefix: "Failed to execute 'structuredClone'",
122+
context: 'Options',
123+
},
124+
);
124125

125126
constserializedData=nativeStructuredClone(value,idlOptions);
126127
returnserializedData;

‎test/parallel/test-structuredClone-global.js‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33
require('../common');
44
constassert=require('assert');
55

6+
constprefix="Failed to execute 'structuredClone'";
7+
constkey='transfer';
8+
constcontext='Options';
9+
constmemberConverterError=`${prefix}: ${key} in ${context} can not be converted to sequence.`;
10+
constdictionaryConverterError=`${prefix}: ${context} cannot be converted to a dictionary`;
11+
612
assert.throws(()=>structuredClone(),{code: 'ERR_MISSING_ARGS'});
7-
assert.throws(()=>structuredClone(undefined,''),{code: 'ERR_INVALID_ARG_TYPE'});
8-
assert.throws(()=>structuredClone(undefined,1),{code: 'ERR_INVALID_ARG_TYPE'});
9-
assert.throws(()=>structuredClone(undefined,{transfer: 1}),{code: 'ERR_INVALID_ARG_TYPE'});
10-
assert.throws(()=>structuredClone(undefined,{transfer: ''}),{code: 'ERR_INVALID_ARG_TYPE'});
11-
assert.throws(()=>structuredClone(undefined,{transfer: null}),{code: 'ERR_INVALID_ARG_TYPE'});
13+
assert.throws(()=>structuredClone(undefined,''),
14+
{code: 'ERR_INVALID_ARG_TYPE',message: dictionaryConverterError});
15+
assert.throws(()=>structuredClone(undefined,1),
16+
{code: 'ERR_INVALID_ARG_TYPE',message: dictionaryConverterError});
17+
assert.throws(()=>structuredClone(undefined,{transfer: 1}),
18+
{code: 'ERR_INVALID_ARG_TYPE',message: memberConverterError});
19+
assert.throws(()=>structuredClone(undefined,{transfer: ''}),
20+
{code: 'ERR_INVALID_ARG_TYPE',message: memberConverterError});
21+
assert.throws(()=>structuredClone(undefined,{transfer: null}),
22+
{code: 'ERR_INVALID_ARG_TYPE',message: memberConverterError});
1223

1324
// Options can be null or undefined.
1425
assert.strictEqual(structuredClone(undefined),undefined);

0 commit comments

Comments
 (0)