Skip to content

Commit

Permalink
chore: improve internal webidl functions (#9606)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacasonato authored Mar 1, 2021
1 parent ded68ab commit 72425ec
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 13 deletions.
2 changes: 1 addition & 1 deletion cli/tests/error_009_op_crates_error.js.out
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[WILDCARD]error: Uncaught TypeError: Failed to construct 'Event': 1 argument, but only 0 present.
[WILDCARD]error: Uncaught TypeError: Failed to construct 'Event': 1 argument required, but only 0 present.
new Event();
^
at [WILDCARD]
Expand Down
98 changes: 87 additions & 11 deletions op_crates/web/00_webidl.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
return new ErrorType(
`${opts.prefix ? opts.prefix + ": " : ""}${
opts.context ? opts.context : "Value"
} ${message}.`,
} ${message}`,
);
}

Expand Down Expand Up @@ -602,7 +602,7 @@
opts.prefix ? opts.prefix + ": " : ""
}${required} argument${
required === 1 ? "" : "s"
}, but only ${length} present.`;
} required, but only ${length} present.`;
throw new TypeError(errMsg);
}
}
Expand Down Expand Up @@ -637,22 +637,26 @@
esMemberValue = esDict[key];
}

const context = `'${key}' of '${name}'${
opts.context ? ` (${opts.context})` : ""
}`;

if (esMemberValue !== undefined) {
const converter = member.converter;
const idlMemberValue = converter(esMemberValue, {
...opts,
context: `${key} of '${name}'${
opts.context ? `(${opts.context})` : ""
}`,
context,
});
idlDict[key] = idlMemberValue;
} else if ("defaultValue" in member) {
const defaultValue = member.defaultValue;
const idlMemberValue = defaultValue;
idlDict[key] = idlMemberValue;
} else if (member.required) {
throw new TypeError(
`can not be converted to '${name}' because ${key} is required in '${name}'.`,
throw makeException(
TypeError,
`can not be converted to '${name}' because '${key}' is required in '${name}'.`,
{ ...opts },
);
}
}
Expand All @@ -670,10 +674,10 @@
const S = String(V);

if (!E.has(S)) {
throw makeException(
TypeError,
`The provided value '${V}' is not a valid enum value of type ${name}.`,
opts,
throw new TypeError(
`${
opts.prefix ? opts.prefix + ": " : ""
}The provided value '${S}' is not a valid enum value of type ${name}.`,
);
}

Expand All @@ -694,12 +698,84 @@
};
}

// https://heycam.github.io/webidl/#es-sequence
function createSequenceConverter(converter) {
return function (V, opts = {}) {
if (typeof V !== "object") {
throw makeException(
TypeError,
"can not be converted to sequence.",
opts,
);
}
const iter = V?.[Symbol.iterator]?.();
if (iter === undefined) {
throw makeException(
TypeError,
"can not be converted to sequence.",
opts,
);
}
const array = [];
while (true) {
const res = iter?.next?.();
if (res === undefined) {
throw makeException(
TypeError,
"can not be converted to sequence.",
opts,
);
}
if (res.done === true) break;
const val = converter(res.value, {
...opts,
context: `${opts.context}, index ${array.length}`,
});
array.push(val);
}
return array;
};
}

const brand = Symbol("[[webidl.brand]]");

function createInterfaceConverter(name, prototype) {
return (V, opts) => {
if (!(V instanceof prototype) || V[brand] !== brand) {
throw makeException(TypeError, `is not of type ${name}.`, opts);
}
return V;
};
}

function createBranded(Type) {
const t = Object.create(Type.prototype);
t[brand] = brand;
return t;
}

function assertBranded(self, prototype) {
if (!(self instanceof prototype) || self[brand] !== brand) {
throw new TypeError("Illegal invocation");
}
}

function illegalConstructor() {
throw new TypeError("Illegal constructor");
}

window.__bootstrap ??= {};
window.__bootstrap.webidl = {
converters,
requiredArguments,
createDictionaryConverter,
createEnumConverter,
createNullableConverter,
createSequenceConverter,
createInterfaceConverter,
brand,
createBranded,
assertBranded,
illegalConstructor,
};
})(this);
39 changes: 38 additions & 1 deletion op_crates/web/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ declare namespace globalThis {
* Convert a value into a `VoidFunction` (() => void).
*/
VoidFunction(v: any, opts?: ValueConverterOpts): () => void;

[type: string]: (v: any, opts: ValueConverterOpts) => any;
};

/**
Expand All @@ -205,7 +207,7 @@ declare namespace globalThis {
declare interface DictionaryMember {
key: string;
converter: (v: any, opts: ValueConverterOpts) => any;
defaultValue?: boolean;
defaultValue?: any;
required?: boolean;
}

Expand All @@ -231,6 +233,41 @@ declare namespace globalThis {
declare function createNullableConverter<T>(
converter: (v: any, opts: ValueConverterOpts) => T,
): (v: any, opts: ValueConverterOpts) => T | null;

/**
* Create a converter that converts a sequence of the inner type.
*/
declare function createSequenceConverter<T>(
converter: (v: any, opts: ValueConverterOpts) => T,
): (v: any, opts: ValueConverterOpts) => T[];

/**
* Throw an illegal constructor error.
*/
declare function illegalConstructor(): never;

/**
* The branding symbol.
*/
declare const brand: unique symbol;

/**
* Create a branded instance of an interface.
*/
declare function createBranded(self: any): any;

/**
* Assert that self is branded.
*/
declare function assertBranded(self: any, type: any): void;

/**
* Create a converter for interfaces.
*/
declare function createInterfaceConverter(
name: string,
prototype: any,
): (v: any, opts: ValueConverterOpts) => any;
}

declare var url: {
Expand Down

0 comments on commit 72425ec

Please sign in to comment.