Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d1965f9

Browse filesBrowse 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
Copy full SHA for d1965f9

File tree

Expand file treeCollapse file tree

3 files changed

+98
-23
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+98
-23
lines changed
Open diff view settings
Collapse file

‎lib/internal/webidl.js‎

Copy file name to clipboardExpand all lines: lib/internal/webidl.js
+63Lines 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+
function createDictionaryConverter(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+
const sortedMembers = ArrayPrototypeToSorted(members, (a, b) => {
282+
if (a.key === b.key) {
283+
return 0;
284+
}
285+
return a.key < b.key ? -1 : 1;
286+
});
287+
288+
return function(
289+
V,
290+
opts = kEmptyObject,
291+
) {
292+
if (V != null && type(V) !== OBJECT) {
293+
throw makeException(
294+
'cannot be converted to a dictionary',
295+
opts,
296+
);
297+
}
298+
299+
const idlDict = { __proto__: null };
300+
for (let i = 0; i < sortedMembers.length; i++) {
301+
const member = sortedMembers[i];
302+
const key = member.key;
303+
let jsMemberValue;
304+
if (V == null) {
305+
jsMemberValue = undefined;
306+
} else {
307+
jsMemberValue = V[key];
308+
}
309+
310+
if (jsMemberValue !== undefined) {
311+
const memberContext = opts.context ? `${key} in ${opts.context}` : `${key}`;
312+
const converter = member.converter;
313+
const idlMemberValue = converter(
314+
jsMemberValue,
315+
{
316+
__proto__: null,
317+
prefix: opts.prefix,
318+
context: memberContext,
319+
},
320+
);
321+
idlDict[key] = idlMemberValue;
322+
} else if (typeof member.defaultValue === 'function') {
323+
const idlMemberValue = member.defaultValue();
324+
idlDict[key] = idlMemberValue;
325+
} else if (member.required) {
326+
throw makeException(
327+
`cannot be converted because of the missing '${key}'`,
328+
opts,
329+
);
330+
}
331+
}
332+
333+
return idlDict;
334+
};
335+
}
336+
275337
// https://webidl.spec.whatwg.org/#es-sequence
276338
function createSequenceConverter(converter) {
277339
return function(V, opts = kEmptyObject) {
@@ -327,6 +389,7 @@ module.exports = {
327389
createEnumConverter,
328390
createInterfaceConverter,
329391
createSequenceConverter,
392+
createDictionaryConverter,
330393
evenRound,
331394
makeException,
332395
};
Collapse file

‎lib/internal/worker/js_transferable.js‎

Copy file name to clipboardExpand all lines: lib/internal/worker/js_transferable.js
+19-18Lines 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
function structuredClone(value, options) {
102113
if (arguments.length === 0) {
103114
throw new ERR_MISSING_ARGS('The value argument must be specified');
104115
}
105116

106-
// TODO(jazelly): implement generic webidl dictionary converter
107-
const prefix = 'Options';
108-
const optionsType = webidl.type(options);
109-
if (optionsType !== 'Undefined' && optionsType !== 'Null' && optionsType !== 'Object') {
110-
throw new ERR_INVALID_ARG_TYPE(
111-
prefix,
112-
['object', 'null', 'undefined'],
113-
options,
114-
);
115-
}
116-
const key = 'transfer';
117-
const idlOptions = { __proto__: null, [key]: [] };
118-
if (options != null && key in options && options[key] !== undefined) {
119-
idlOptions[key] = webidl.converters['sequence<object>'](options[key], {
117+
const idlOptions = 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
const serializedData = nativeStructuredClone(value, idlOptions);
126127
return serializedData;
Collapse file

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

Copy file name to clipboardExpand all lines: test/parallel/test-structuredClone-global.js
+16-5Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33
require('../common');
44
const assert = require('assert');
55

6+
const prefix = "Failed to execute 'structuredClone'";
7+
const key = 'transfer';
8+
const context = 'Options';
9+
const memberConverterError = `${prefix}: ${key} in ${context} can not be converted to sequence.`;
10+
const dictionaryConverterError = `${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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.