Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/constructs/async-iterable.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class AsyncIterable {

this.interface.addMethod(this.interface.defaultWhence, key, [], `
if (!exports.is(this)) {
throw new TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'${key}' called on an object that is not a valid instance of ${this.interface.name}.");
}

${conv.body}
Expand Down
8 changes: 4 additions & 4 deletions lib/constructs/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ class Attribute {

const async = this.idl.idlType.generic === "Promise";
const promiseHandlingBefore = async ? `try {` : ``;
const promiseHandlingAfter = async ? `} catch (e) { return Promise.reject(e); }` : ``;
const promiseHandlingAfter = async ? `} catch (e) { return ctorRegistry["%Promise%"].reject(e); }` : ``;

let brandCheck = `
if (!exports.is(esValue)) {
throw new TypeError("'$KEYWORD$ ${this.idl.name}' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'$KEYWORD$ ${this.idl.name}' called on an object that is not a valid instance of ${this.interface.name}.");
}
`;
let getterBody = `return utils.tryWrapperForImpl(esValue[implSymbol]["${this.idl.name}"]);`;
Expand Down Expand Up @@ -150,7 +150,7 @@ class Attribute {
setterBody = `
const Q = esValue["${this.idl.name}"];
if (!utils.isObject(Q)) {
throw new TypeError("Property '${this.idl.name}' is not an object");
throw new ctorRegistry["%TypeError%"]("Property '${this.idl.name}' is not an object");
}
`;

Expand Down Expand Up @@ -180,7 +180,7 @@ class Attribute {
addMethod("toString", [], `
const esValue = this;
if (!exports.is(esValue)) {
throw new TypeError("'toString' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'toString' called on an object that is not a valid instance of ${this.interface.name}.");
}

${getterBody}
Expand Down
6 changes: 3 additions & 3 deletions lib/constructs/callback-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CallbackFunction {
"" :
`
if (typeof value !== "function") {
throw new TypeError(context + " is not a function");
throw new ctorRegistry["%TypeError%"](context + " is not a function");
}
`;

Expand Down Expand Up @@ -109,7 +109,7 @@ class CallbackFunction {
}

this.str += `
exports.convert = (value, { context = "The provided value" } = {}) => {
exports.convert = (value, { context = "The provided value", ctorRegistry = { "%TypeError%": TypeError, "%Number%": Number, "%Promise%": Promise, "%String%": String } } = {}) => {
${assertCallable}
function invokeTheCallbackFunction(${inputArgs}) {
const thisArg = utils.tryWrapperForImpl(this);
Expand Down Expand Up @@ -144,7 +144,7 @@ class CallbackFunction {
if (isAsync) {
this.str += `
} catch (err) {
return Promise.reject(err);
return ctorRegistry["%Promise%"].reject(err);
}
`;
}
Expand Down
11 changes: 6 additions & 5 deletions lib/constructs/callback-interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ class CallbackInterface {
}

this.str += `
exports.convert = function convert(value, { context = "The provided value" } = {}) {
exports.convert = (value, { context = "The provided value", ctorRegistry = { "%TypeError%": TypeError, "%Number%": Number, "%Promise%": Promise, "%String%": String } } = {}) => {
if (!utils.isObject(value)) {
throw new TypeError(\`\${context} is not an object.\`);
throw new ctorRegistry["%TypeError%"](\`\${context} is not an object.\`);
}

function callTheUserObjectsOperation(${argNames.join(", ")}) {
Expand All @@ -115,7 +115,7 @@ class CallbackInterface {
if (typeof O !== "function") {
X = O[${utils.stringifyPropertyName(opName)}];
if (typeof X !== "function") {
throw new TypeError(\`\${context} does not correctly implement ${name}.\`)
throw new ctorRegistry["%TypeError%"](\`\${context} does not correctly implement ${name}.\`)
}
thisArg = O;
}
Expand Down Expand Up @@ -151,7 +151,7 @@ class CallbackInterface {
if (isAsync) {
this.str += `
} catch (err) {
return Promise.reject(err);
return ctorRegistry["%Promise%"].reject(err);
}
`;
}
Expand Down Expand Up @@ -215,8 +215,9 @@ class CallbackInterface {
return;
}

const ctorRegistry = utils.initCtorRegistry(globalObject);
const ${name} = () => {
throw new TypeError("Illegal invocation");
throw new ctorRegistry["%TypeError%"]("Illegal invocation");
};
`;

Expand Down
12 changes: 6 additions & 6 deletions lib/constructs/dictionary.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Dictionary {
if (field.required) {
str += `
else {
throw new TypeError("${field.name} is required in '${this.name}'");
throw new ctorRegistry["%TypeError%"]("${field.name} is required in '${this.name}'");
}
`;
} else if (field.default) {
Expand All @@ -76,26 +76,26 @@ class Dictionary {

generate() {
this.str += `
exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => {
exports._convertInherit = (obj, ret, { context = "The provided value", ctorRegistry } = {}) => {
`;

if (this.idl.inheritance) {
this.str += `
${this.idl.inheritance}._convertInherit(obj, ret, { context });
${this.idl.inheritance}._convertInherit(obj, ret, { context, ctorRegistry });
`;
}

this.str += `
${this._generateConversions()}
};

exports.convert = function convert(obj, { context = "The provided value" } = {}) {
exports.convert = (obj, { context = "The provided value", ctorRegistry = { "%TypeError%": TypeError, "%Number%": Number, "%Promise%": Promise, "%String%": String } } = {}) => {
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
throw new TypeError(\`\${context} is not an object.\`);
throw new ctorRegistry["%TypeError%"](\`\${context} is not an object.\`);
}

const ret = Object.create(null);
exports._convertInherit(obj, ret, { context });
exports._convertInherit(obj, ret, { context, ctorRegistry });
return ret;
};
`;
Expand Down
4 changes: 2 additions & 2 deletions lib/constructs/enumeration.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ class Enumeration {
const enumerationValues = new Set(${JSON.stringify([...values])});
exports.enumerationValues = enumerationValues;

exports.convert = function convert(value, { context = "The provided value" } = {}) {
exports.convert = (value, { context = "The provided value", ctorRegistry = { "%TypeError%": TypeError } } = {}) => {
const string = \`\${value}\`;
if (!enumerationValues.has(string)) {
throw new TypeError(\`\${context} '\${string}' is not a valid enumeration value for ${this.name}\`);
throw new ctorRegistry["%TypeError%"](\`\${context} '\${string}' is not a valid enumeration value for ${this.name}\`);
}
return string;
};
Expand Down
16 changes: 8 additions & 8 deletions lib/constructs/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,12 @@ class Interface {
next() {
const internal = this && this[utils.iterInternalSymbol];
if (!internal) {
return Promise.reject(new TypeError("next() called on a value that is not a ${this.name} async iterator object"));
return ctorRegistry["%Promise%"].reject(new ctorRegistry["%TypeError%"]("next() called on a value that is not a ${this.name} async iterator object"));
}

const nextSteps = () => {
if (internal.isFinished) {
return Promise.resolve({ value: undefined, done: true });
return ctorRegistry["%Promise%"].resolve({ value: undefined, done: true });
}

const nextPromise = internal.target[implSymbol][utils.asyncIteratorNext](this);
Expand Down Expand Up @@ -481,12 +481,12 @@ class Interface {
return(value) {
const internal = this && this[utils.iterInternalSymbol];
if (!internal) {
return Promise.reject(new TypeError("return() called on a value that is not a ${this.name} async iterator object"));
return ctorRegistry["%Promise%"].reject(new ctorRegistry["%TypeError%"]("return() called on a value that is not a ${this.name} async iterator object"));
}

const returnSteps = () => {
if (internal.isFinished) {
return Promise.resolve({ value, done: true });
return ctorRegistry["%Promise%"].resolve({ value, done: true });
}
internal.isFinished = true;

Expand Down Expand Up @@ -516,7 +516,7 @@ class Interface {
next() {
const internal = this && this[utils.iterInternalSymbol];
if (!internal) {
throw new TypeError("next() called on a value that is not a ${this.name} iterator object");
throw new ctorRegistry["%TypeError%"]("next() called on a value that is not a ${this.name} iterator object");
}

const { target, kind, index } = internal;
Expand Down Expand Up @@ -600,11 +600,11 @@ class Interface {
exports.isImpl = value => {
return utils.isObject(value) && value instanceof Impl.implementation;
};
exports.convert = (value, { context = "The provided value" } = {}) => {
exports.convert = (value, { context = "The provided value", ctorRegistry = { "%TypeError%": TypeError } } = {}) => {
if (exports.is(value)) {
return utils.implForWrapper(value);
}
throw new TypeError(\`\${context} is not of type '${this.name}'.\`);
throw new ctorRegistry["%TypeError%"](\`\${context} is not of type '${this.name}'.\`);
};
`;

Expand Down Expand Up @@ -1358,7 +1358,7 @@ class Interface {
`;
} else {
body = `
throw new TypeError("Illegal constructor");
throw new ctorRegistry["%TypeError%"]("Illegal constructor");
`;
}

Expand Down
10 changes: 5 additions & 5 deletions lib/constructs/iterable.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Iterable {
generateFunction(key, kind) {
this.interface.addMethod(this.interface.defaultWhence, key, [], `
if (!exports.is(this)) {
throw new TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'${key}' called on an object that is not a valid instance of ${this.interface.name}.");
}
return exports.createDefaultIterator(globalObject, this, "${kind}");
`);
Expand All @@ -42,14 +42,14 @@ class Iterable {
this.interface.addProperty(whence, Symbol.iterator, `${this.interface.name}.prototype.entries`);
this.interface.addMethod(whence, "forEach", ["callback"], `
if (!exports.is(this)) {
throw new TypeError("'forEach' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'forEach' called on an object that is not a valid instance of ${this.interface.name}.");
}
if (arguments.length < 1) {
throw new TypeError("Failed to execute 'forEach' on '${this.name}': 1 argument required, " +
"but only 0 present.");
throw new ctorRegistry["%TypeError%"]("Failed to execute 'forEach' on '${this.name}': 1 argument required, but only 0 present.");
}
callback = ${requires.addRelative("Function")}.convert(callback, {
context: "Failed to execute 'forEach' on '${this.name}': The callback provided as parameter 1"
context: "Failed to execute 'forEach' on '${this.name}': The callback provided as parameter 1",
ctorRegistry
});
const thisArg = arguments[1];
let pairs = Array.from(this[implSymbol]);
Expand Down
4 changes: 2 additions & 2 deletions lib/constructs/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Operation {
const whence = this.getWhence();
const async = this.isAsync();
const promiseHandlingBefore = async ? `try {` : ``;
const promiseHandlingAfter = async ? `} catch (e) { return Promise.reject(e); }` : ``;
const promiseHandlingAfter = async ? `} catch (e) { return ctorRegistry["%Promise%"].reject(e); }` : ``;
const hasCallWithGlobal = this.hasCallWithGlobal();

const type = this.static ? "static operation" : "regular operation";
Expand All @@ -115,7 +115,7 @@ class Operation {
str += `
const esValue = this !== null && this !== undefined ? this : globalObject;
if (!exports.is(esValue)) {
throw new TypeError("'${this.name}' called on an object that is not a valid instance of ${this.interface.name}.");
throw new ctorRegistry["%TypeError%"]("'${this.name}' called on an object that is not a valid instance of ${this.interface.name}.");
}
`;
}
Expand Down
20 changes: 19 additions & 1 deletion lib/output/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ const sameObjectCaches = Symbol("SameObject caches");
const ctorRegistrySymbol = Symbol.for("[webidl2js] constructor registry");

// This only contains the intrinsic names that are referenced from the `ctorRegistry`:
const intrinsicConstructors = ["Array"];
const intrinsicConstructors = [
"Array",
// Number and String are used by `webidl-conversions`
"Number",
"Promise",
"String",
"TypeError"
];

function initCtorRegistry(globalObject) {
if (hasOwn(globalObject, ctorRegistrySymbol)) {
Expand All @@ -45,6 +52,16 @@ function initCtorRegistry(globalObject) {
return ctorRegistry;
}

// The result is used as the `globals` property of the `options` parameter for `webidl-conversions`:
function conversionGlobalsFromCtorRegistry(ctorRegistry) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's stop storing the intrinsics under "%TypeError" and instead store them under "TypeError". Then we can get rid of this function entirely and just pass the ctorRegistry.

const globals = Object.create(null);
for (const intrinsic of intrinsicConstructors) {
globals[intrinsic] = ctorRegistry[`%${intrinsic}%`];
}

return globals;
}

function getSameObject(wrapper, prop, creator) {
if (!wrapper[sameObjectCaches]) {
wrapper[sameObjectCaches] = Object.create(null);
Expand Down Expand Up @@ -148,6 +165,7 @@ module.exports = exports = {
getSameObject,
ctorRegistrySymbol,
initCtorRegistry,
conversionGlobalsFromCtorRegistry,
wrapperForImpl,
implForWrapper,
tryWrapperForImpl,
Expand Down
7 changes: 3 additions & 4 deletions lib/parameters.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,7 @@ module.exports.generateOverloadConversions = function (ctx, typeOfOp, name, pare
const plural = minArgs > 1 ? "s" : "";
str += `
if (arguments.length < ${minArgs}) {
throw new TypeError("${errPrefix}${minArgs} argument${plural} required, but only " + arguments.length +
" present.");
throw new ctorRegistry["%TypeError%"](\`${errPrefix}${minArgs} argument${plural} required, but only \${arguments.length} present.\`);
}
`;
}
Expand All @@ -127,7 +126,7 @@ module.exports.generateOverloadConversions = function (ctx, typeOfOp, name, pare
.filter(o => o.typeList.length === numArgs);
if (S.length === 0) {
switchCases.push(`
throw new TypeError("${errPrefix}only " + arguments.length + " arguments present.");
throw new ctorRegistry["%TypeError%"](\`${errPrefix}only \${arguments.length} arguments present.\`);
`);
continue;
}
Expand Down Expand Up @@ -303,7 +302,7 @@ module.exports.generateOverloadConversions = function (ctx, typeOfOp, name, pare
} else if (any.length) {
possibilities.push(`{ ${continued(any[0], i)} }`);
} else {
possibilities.push(`throw new TypeError("${errPrefix}No such overload");`);
possibilities.push(`throw new ctorRegistry["%TypeError%"]("${errPrefix}No such overload");`);
}

caseSrc += possibilities.join(" else ");
Expand Down
Loading