Comparing version 16.2.0 to 17.0.0
@@ -32,3 +32,7 @@ "use strict"; | ||
const conv = generateAsyncIteratorArgConversions( | ||
this.ctx, this.idl, this.interface, `Failed to execute '${key}' on '${this.interface.name}': `); | ||
this.ctx, | ||
this.idl, | ||
this.interface, | ||
`Failed to execute '${key}' on '${this.interface.name}': ` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -38,3 +42,3 @@ | ||
if (!exports.is(this)) { | ||
throw new TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
throw new globalObject.TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
} | ||
@@ -44,3 +48,3 @@ | ||
const asyncIterator = exports.createDefaultAsyncIterator(this, "${kind}"); | ||
const asyncIterator = exports.createDefaultAsyncIterator(globalObject, this, "${kind}"); | ||
if (this[implSymbol][utils.asyncIteratorInit]) { | ||
@@ -47,0 +51,0 @@ this[implSymbol][utils.asyncIteratorInit](asyncIterator, args); |
@@ -16,6 +16,18 @@ "use strict"; | ||
getWhence() { | ||
const { idl } = this; | ||
const isOnInstance = utils.isOnInstance(idl, this.interface.idl); | ||
if (utils.getExtAttr(idl.extAttrs, "LegacyUnforgeable")) { | ||
return "unforgeables"; | ||
} | ||
return isOnInstance ? "instance" : "prototype"; | ||
} | ||
generate() { | ||
const requires = new utils.RequiresMap(this.ctx); | ||
const configurable = !utils.getExtAttr(this.idl.extAttrs, "LegacyUnforgeable"); | ||
const whence = this.getWhence(); | ||
const configurable = whence !== "unforgeables"; | ||
const shouldReflect = | ||
@@ -25,11 +37,9 @@ this.idl.extAttrs.some(attr => attr.name.startsWith("Reflect")) && this.ctx.processReflect !== null; | ||
const onInstance = utils.isOnInstance(this.idl, this.interface.idl); | ||
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 globalObject.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 globalObject.TypeError("'$KEYWORD$ ${this.idl.name}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
} | ||
@@ -45,3 +55,3 @@ `; | ||
this.interface.addStaticMethod.bind(this.interface) : | ||
this.interface.addMethod.bind(this.interface, onInstance ? "instance" : "prototype"); | ||
this.interface.addMethod.bind(this.interface, whence); | ||
@@ -108,4 +118,9 @@ if (this.static) { | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "V", this.idl.idlType, this.idl.extAttrs, this.interface.name, | ||
`"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"`); | ||
this.ctx, | ||
"V", | ||
this.idl.idlType, | ||
this.idl.extAttrs, | ||
this.interface.name, | ||
`"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -142,3 +157,3 @@ idlConversion = conv.body; | ||
if (!utils.isObject(Q)) { | ||
throw new TypeError("Property '${this.idl.name}' is not an object"); | ||
throw new globalObject.TypeError("Property '${this.idl.name}' is not an object"); | ||
} | ||
@@ -158,6 +173,10 @@ `; | ||
} else if (legacyLenientSetter) { | ||
addMethod(this.idl.name, ["V"], legacyLenientThis ? "" : ` | ||
const esValue = this !== null && this !== undefined ? this : globalObject; | ||
${brandCheck} | ||
`, "set", { configurable }); | ||
const body = legacyLenientThis ? | ||
"" : | ||
` | ||
const esValue = this !== null && this !== undefined ? this : globalObject; | ||
${brandCheck} | ||
`; | ||
addMethod(this.idl.name, ["V"], body, "set", { configurable }); | ||
} | ||
@@ -170,3 +189,3 @@ } | ||
if (!exports.is(esValue)) { | ||
throw new TypeError("'toString' called on an object that is not a valid instance of ${this.interface.name}."); | ||
throw new globalObject.TypeError("'toString' called on an object that is not a valid instance of ${this.interface.name}."); | ||
} | ||
@@ -173,0 +192,0 @@ |
@@ -24,10 +24,12 @@ "use strict"; | ||
const assertCallable = legacyTreatNonObjectAsNull ? "" : ` | ||
if (typeof value !== "function") { | ||
throw new TypeError(context + " is not a function"); | ||
} | ||
`; | ||
const assertCallable = legacyTreatNonObjectAsNull ? | ||
"" : | ||
` | ||
if (typeof value !== "function") { | ||
throw new globalObject.TypeError(context + " is not a function"); | ||
} | ||
`; | ||
let returnIDL = ""; | ||
if (idl.idlType.idlType !== "void") { | ||
if (idl.idlType.idlType !== "undefined") { | ||
const conv = Types.generateTypeConversion(this.ctx, "callResult", idl.idlType, [], this.name, "context"); | ||
@@ -111,9 +113,5 @@ this.requires.merge(conv.requires); | ||
this.str += ` | ||
exports.convert = (value, { context = "The provided value" } = {}) => { | ||
exports.convert = (globalObject, value, { context = "The provided value" } = {}) => { | ||
${assertCallable} | ||
function invokeTheCallbackFunction(${inputArgs}) { | ||
if (new.target !== undefined) { | ||
throw new Error("Internal error: invokeTheCallbackFunction is not a constructor"); | ||
} | ||
const thisArg = utils.tryWrapperForImpl(this); | ||
@@ -151,3 +149,3 @@ let callResult; | ||
} catch (err) { | ||
return Promise.reject(err); | ||
return globalObject.Promise.reject(err); | ||
} | ||
@@ -154,0 +152,0 @@ `; |
@@ -97,5 +97,5 @@ "use strict"; | ||
this.str += ` | ||
exports.convert = function convert(value, { context = "The provided value" } = {}) { | ||
exports.convert = (globalObject, value, { context = "The provided value" } = {}) => { | ||
if (!utils.isObject(value)) { | ||
throw new TypeError(\`\${context} is not an object.\`); | ||
throw new globalObject.TypeError(\`\${context} is not an object.\`); | ||
} | ||
@@ -119,3 +119,3 @@ | ||
if (typeof X !== "function") { | ||
throw new TypeError(\`\${context} does not correctly implement ${name}.\`) | ||
throw new globalObject.TypeError(\`\${context} does not correctly implement ${name}.\`) | ||
} | ||
@@ -144,3 +144,3 @@ thisArg = O; | ||
if (operation.idlType.idlType !== "void") { | ||
if (operation.idlType.idlType !== "undefined") { | ||
const conv = Types.generateTypeConversion(this.ctx, "callResult", operation.idlType, [], name, "context"); | ||
@@ -157,3 +157,3 @@ this.requires.merge(conv.requires); | ||
} catch (err) { | ||
return Promise.reject(err); | ||
return globalObject.Promise.reject(err); | ||
} | ||
@@ -222,4 +222,5 @@ `; | ||
const ctorRegistry = utils.initCtorRegistry(globalObject); | ||
const ${name} = () => { | ||
throw new TypeError("Illegal invocation"); | ||
throw new globalObject.TypeError("Illegal invocation"); | ||
}; | ||
@@ -226,0 +227,0 @@ `; |
@@ -17,3 +17,3 @@ "use strict"; | ||
const fields = []; | ||
const members = this.idl.members; | ||
const { members } = this.idl; | ||
members.forEach(member => { | ||
@@ -37,3 +37,9 @@ if (member.type !== "field") { | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "value", typeConversion, argAttrs, this.name, `context + " has member '${field.name}' that"`); | ||
this.ctx, | ||
"value", | ||
typeConversion, | ||
argAttrs, | ||
this.name, | ||
`context + " has member '${field.name}' that"` | ||
); | ||
this.requires.merge(conv.requires); | ||
@@ -54,3 +60,3 @@ | ||
else { | ||
throw new TypeError("${field.name} is required in '${this.name}'"); | ||
throw new globalObject.TypeError("${field.name} is required in '${this.name}'"); | ||
} | ||
@@ -76,3 +82,3 @@ `; | ||
this.str += ` | ||
exports._convertInherit = (obj, ret, { context = "The provided value" } = {}) => { | ||
exports._convertInherit = (globalObject, obj, ret, { context = "The provided value" } = {}) => { | ||
`; | ||
@@ -82,3 +88,3 @@ | ||
this.str += ` | ||
${this.idl.inheritance}._convertInherit(obj, ret, { context }); | ||
${this.idl.inheritance}._convertInherit(globalObject, obj, ret, { context }); | ||
`; | ||
@@ -91,9 +97,9 @@ } | ||
exports.convert = function convert(obj, { context = "The provided value" } = {}) { | ||
exports.convert = (globalObject, obj, { context = "The provided value" } = {}) => { | ||
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") { | ||
throw new TypeError(\`\${context} is not an object.\`); | ||
throw new globalObject.TypeError(\`\${context} is not an object.\`); | ||
} | ||
const ret = Object.create(null); | ||
exports._convertInherit(obj, ret, { context }); | ||
exports._convertInherit(globalObject, obj, ret, { context }); | ||
return ret; | ||
@@ -100,0 +106,0 @@ }; |
@@ -21,6 +21,6 @@ "use strict"; | ||
exports.convert = function convert(value, { context = "The provided value" } = {}) { | ||
exports.convert = (globalObject, value, { context = "The provided value" } = {}) => { | ||
const string = \`\${value}\`; | ||
if (!enumerationValues.has(string)) { | ||
throw new TypeError(\`\${context} '\${string}' is not a valid enumeration value for ${this.name}\`); | ||
throw new globalObject.TypeError(\`\${context} '\${string}' is not a valid enumeration value for ${this.name}\`); | ||
} | ||
@@ -27,0 +27,0 @@ return string; |
@@ -38,6 +38,2 @@ "use strict"; | ||
for (const member of this.idl.members) { | ||
member.definingInterface = this.name; | ||
} | ||
this.str = null; | ||
@@ -61,6 +57,6 @@ this.opts = opts; | ||
this.stringifier = null; | ||
this.needsPerGlobalProxyHandler = false; | ||
this.iterable = null; | ||
this._analyzed = false; | ||
this._needsUnforgeablesObject = false; | ||
@@ -79,18 +75,14 @@ this._outputMethods = new Map(); | ||
const exposed = utils.getExtAttr(this.idl.extAttrs, "Exposed"); | ||
if (exposed) { | ||
if (!exposed.rhs || (exposed.rhs.type !== "identifier" && exposed.rhs.type !== "identifier-list")) { | ||
throw new Error(`[Exposed] must take an identifier or an identifier list in interface ${this.name}`); | ||
} | ||
if (!exposed) { | ||
throw new Error(`Interface ${this.name} lacks [Exposed]`); | ||
} | ||
if (exposed.rhs.type === "identifier") { | ||
this.exposed = new Set([exposed.rhs.value]); | ||
} else { | ||
this.exposed = new Set(exposed.rhs.value.map(token => token.value)); | ||
} | ||
} else { | ||
this.exposed = new Set(); | ||
if (!exposed.rhs || (exposed.rhs.type !== "identifier" && exposed.rhs.type !== "identifier-list")) { | ||
throw new Error(`[Exposed] must take an identifier or an identifier list in interface ${this.name}`); | ||
} | ||
if (!exposed && !utils.getExtAttr(this.idl.extAttrs, "LegacyNoInterfaceObject")) { | ||
throw new Error(`Interface ${this.name} has neither [Exposed] nor [LegacyNoInterfaceObject]`); | ||
if (exposed.rhs.type === "identifier") { | ||
this.exposed = new Set([exposed.rhs.value]); | ||
} else { | ||
this.exposed = new Set(exposed.rhs.value.map(token => token.value)); | ||
} | ||
@@ -123,3 +115,3 @@ | ||
// whence is either "instance" or "prototype" | ||
// whence is either "instance", "prototype" or "unforgeables" | ||
// type is either "regular", "get", or "set" | ||
@@ -131,3 +123,3 @@ addMethod(whence, propName, args, body, type = "regular", { | ||
} = {}) { | ||
if (whence !== "instance" && whence !== "prototype") { | ||
if (whence !== "instance" && whence !== "prototype" && whence !== "unforgeables") { | ||
throw new Error(`Internal error: Invalid whence ${whence}`); | ||
@@ -155,2 +147,6 @@ } | ||
this._outputMethods.set(propName, { whence, type, args, body, descriptor }); | ||
if (whence === "unforgeables" && !this.isGlobal) { | ||
this._needsUnforgeablesObject = true; | ||
} | ||
} | ||
@@ -213,12 +209,12 @@ | ||
let msg = `Invalid getter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`; | ||
if (member.definingInterface !== this.name) { | ||
msg += ` (defined in ${member.definingInterface})`; | ||
if (member.parent.name !== this.name) { | ||
msg += ` (defined in ${member.parent.name})`; | ||
} | ||
msg += ": "; | ||
if (member.arguments.length !== 1) { | ||
throw new Error(msg + `1 argument should be present, found ${member.arguments.length}`); | ||
throw new Error(`${msg}1 argument should be present, found ${member.arguments.length}`); | ||
} | ||
if (isIndexed(member)) { | ||
if (this.indexedGetter) { | ||
throw new Error(msg + "duplicated indexed getter"); | ||
throw new Error(`${msg}duplicated indexed getter`); | ||
} | ||
@@ -228,7 +224,7 @@ this.indexedGetter = member; | ||
if (this.namedGetter) { | ||
throw new Error(msg + "duplicated named getter"); | ||
throw new Error(`${msg}duplicated named getter`); | ||
} | ||
this.namedGetter = member; | ||
} else { | ||
throw new Error(msg + "getter is neither indexed nor named"); | ||
throw new Error(`${msg}getter is neither indexed nor named`); | ||
} | ||
@@ -238,4 +234,4 @@ } | ||
let msg = `Invalid setter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`; | ||
if (member.definingInterface !== this.name) { | ||
msg += ` (defined in ${member.definingInterface})`; | ||
if (member.parent.name !== this.name) { | ||
msg += ` (defined in ${member.parent.name})`; | ||
} | ||
@@ -245,22 +241,16 @@ msg += ": "; | ||
if (member.arguments.length !== 2) { | ||
throw new Error(msg + `2 arguments should be present, found ${member.arguments.length}`); | ||
throw new Error(`${msg}2 arguments should be present, found ${member.arguments.length}`); | ||
} | ||
if (isIndexed(member)) { | ||
if (this.indexedSetter) { | ||
throw new Error(msg + "duplicated indexed setter"); | ||
throw new Error(`${msg}duplicated indexed setter`); | ||
} | ||
this.indexedSetter = member; | ||
if (utils.hasCEReactions(member)) { | ||
this.needsPerGlobalProxyHandler = true; | ||
} | ||
} else if (isNamed(member)) { | ||
if (this.namedSetter) { | ||
throw new Error(msg + "duplicated named setter"); | ||
throw new Error(`${msg}duplicated named setter`); | ||
} | ||
this.namedSetter = member; | ||
if (utils.hasCEReactions(member)) { | ||
this.needsPerGlobalProxyHandler = true; | ||
} | ||
} else { | ||
throw new Error(msg + "setter is neither indexed nor named"); | ||
throw new Error(`${msg}setter is neither indexed nor named`); | ||
} | ||
@@ -270,4 +260,4 @@ } | ||
let msg = `Invalid deleter ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`; | ||
if (member.definingInterface !== this.name) { | ||
msg += ` (defined in ${member.definingInterface})`; | ||
if (member.parent.name !== this.name) { | ||
msg += ` (defined in ${member.parent.name})`; | ||
} | ||
@@ -277,14 +267,11 @@ msg += ": "; | ||
if (member.arguments.length !== 1) { | ||
throw new Error(msg + `1 arguments should be present, found ${member.arguments.length}`); | ||
throw new Error(`${msg}1 arguments should be present, found ${member.arguments.length}`); | ||
} | ||
if (isNamed(member)) { | ||
if (this.namedDeleter) { | ||
throw new Error(msg + "duplicated named deleter"); | ||
throw new Error(`${msg}duplicated named deleter`); | ||
} | ||
this.namedDeleter = member; | ||
if (utils.hasCEReactions(member)) { | ||
this.needsPerGlobalProxyHandler = true; | ||
} | ||
} else { | ||
throw new Error(msg + "deleter is not named"); | ||
throw new Error(`${msg}deleter is not named`); | ||
} | ||
@@ -336,4 +323,4 @@ } | ||
let msg = `Invalid stringifier ${member.name ? `"${member.name}" ` : ""}on interface ${this.name}`; | ||
if (member.definingInterface !== this.name) { | ||
msg += ` (defined in ${member.definingInterface})`; | ||
if (member.parent.name !== this.name) { | ||
msg += ` (defined in ${member.parent.name})`; | ||
} | ||
@@ -349,9 +336,9 @@ msg += ": "; | ||
if (member.arguments.length > 0) { | ||
throw new Error(msg + "takes more than zero arguments"); | ||
throw new Error(`${msg}takes more than zero arguments`); | ||
} | ||
if (member.idlType.idlType !== "DOMString" || member.idlType.nullable) { | ||
throw new Error(msg + "returns something other than a plain DOMString"); | ||
throw new Error(`${msg}returns something other than a plain DOMString`); | ||
} | ||
if (this.stringifier) { | ||
throw new Error(msg + "duplicated stringifier"); | ||
throw new Error(`${msg}duplicated stringifier`); | ||
} | ||
@@ -363,11 +350,11 @@ const op = new Operation(this.ctx, this, member); | ||
if (member.special === "static") { | ||
throw new Error(msg + "keyword cannot be placed on static attribute"); | ||
throw new Error(`${msg}keyword cannot be placed on static attribute`); | ||
} | ||
if (member.idlType.idlType !== "DOMString" && member.idlType.idlType !== "USVString" || | ||
if ((member.idlType.idlType !== "DOMString" && member.idlType.idlType !== "USVString") || | ||
member.idlType.nullable) { | ||
throw new Error(msg + "attribute can only be of type DOMString or USVString"); | ||
throw new Error(`${msg}attribute can only be of type DOMString or USVString`); | ||
} | ||
// Implemented in Attribute class. | ||
} else { | ||
throw new Error(msg + `keyword placed on incompatible type ${member.type}`); | ||
throw new Error(`${msg}keyword placed on incompatible type ${member.type}`); | ||
} | ||
@@ -380,3 +367,3 @@ this.stringifier = member; | ||
throw new Error(`Iterable interface ${this.name} inherits from another iterable interface ` + | ||
`${member.definingInterface}`); | ||
`${member.parent.name}`); | ||
} | ||
@@ -407,4 +394,4 @@ | ||
let msg = `${member.name} is forbidden in interface ${this.name}`; | ||
if (member.definingInterface !== this.name) { | ||
msg += ` (defined in ${member.definingInterface})`; | ||
if (member.parent.name !== this.name) { | ||
msg += ` (defined in ${member.parent.name})`; | ||
} | ||
@@ -440,21 +427,23 @@ throw new Error(msg); | ||
generateIterator() { | ||
if (!this.iterable) { | ||
generateInstallIteratorPrototype() { | ||
const { iterable } = this; | ||
if (!iterable) { | ||
return; | ||
} | ||
if (this.iterable.isAsync) { | ||
if (iterable.isAsync) { | ||
this.requires.addRaw("newObjectInRealm", "utils.newObjectInRealm"); | ||
this.str += ` | ||
const AsyncIteratorPrototype = Object.create(utils.AsyncIteratorPrototype, { | ||
[Symbol.toStringTag]: { | ||
value: "${this.name} AsyncIterator", | ||
configurable: true | ||
} | ||
}); | ||
Object.assign(AsyncIteratorPrototype, { | ||
ctorRegistry["${this.name} AsyncIterator"] = | ||
Object.create(ctorRegistry["%AsyncIteratorPrototype%"], { | ||
[Symbol.toStringTag]: { | ||
value: "${this.name} AsyncIterator", | ||
configurable: true | ||
} | ||
}); | ||
utils.define(ctorRegistry["${this.name} AsyncIterator"], { | ||
next() { | ||
const internal = this && this[utils.iterInternalSymbol]; | ||
if (!internal) { | ||
return Promise.reject(new TypeError("next() called on a value that is not an async iterator prototype object")); | ||
return globalObject.Promise.reject(new globalObject.TypeError("next() called on a value that is not a ${this.name} async iterator object")); | ||
} | ||
@@ -464,3 +453,3 @@ | ||
if (internal.isFinished) { | ||
return Promise.resolve({ value: undefined, done: true }); | ||
return globalObject.Promise.resolve(newObjectInRealm(globalObject, { value: undefined, done: true })); | ||
} | ||
@@ -474,11 +463,11 @@ | ||
internal.isFinished = true; | ||
return { value: undefined, done: true }; | ||
return newObjectInRealm(globalObject, { value: undefined, done: true }); | ||
}`; | ||
if (this.iterable.isPair) { | ||
if (iterable.isPair) { | ||
this.str += ` | ||
return utils.iteratorResult(next.map(utils.tryWrapperForImpl), kind); | ||
return newObjectInRealm(globalObject, utils.iteratorResult(next.map(utils.tryWrapperForImpl), kind)); | ||
`; | ||
} else { | ||
this.str += ` | ||
return { value: utils.tryWrapperForImpl(next), done: false }; | ||
return newObjectInRealm(globalObject, { value: utils.tryWrapperForImpl(next), done: false }); | ||
`; | ||
@@ -503,3 +492,3 @@ } | ||
if (this.iterable.hasReturnSteps) { | ||
if (iterable.hasReturnSteps) { | ||
this.str += ` | ||
@@ -509,3 +498,3 @@ return(value) { | ||
if (!internal) { | ||
return Promise.reject(new TypeError("return() called on a value that is not an async iterator prototype object")); | ||
return globalObject.Promise.reject(new globalObject.TypeError("return() called on a value that is not a ${this.name} async iterator object")); | ||
} | ||
@@ -515,3 +504,3 @@ | ||
if (internal.isFinished) { | ||
return Promise.resolve({ value, done: true }); | ||
return globalObject.Promise.resolve(newObjectInRealm(globalObject, { value, done: true })); | ||
} | ||
@@ -526,3 +515,3 @@ internal.isFinished = true; | ||
returnSteps(); | ||
return returnPromise.then(() => ({ value, done: true })); | ||
return returnPromise.then(() => newObjectInRealm(globalObject, { value, done: true })); | ||
} | ||
@@ -534,10 +523,19 @@ `; | ||
`; | ||
} else if (this.iterable.isPair) { | ||
} else if (iterable.isPair) { | ||
this.requires.addRaw("newObjectInRealm", "utils.newObjectInRealm"); | ||
this.str += ` | ||
const IteratorPrototype = Object.create(utils.IteratorPrototype, { | ||
next: { | ||
value: function next() { | ||
ctorRegistry["${this.name} Iterator"] = | ||
Object.create(ctorRegistry["%IteratorPrototype%"], { | ||
[Symbol.toStringTag]: { | ||
configurable: true, | ||
value: "${this.name} Iterator" | ||
} | ||
}); | ||
utils.define( | ||
ctorRegistry["${this.name} Iterator"], | ||
{ | ||
next() { | ||
const internal = this && this[utils.iterInternalSymbol]; | ||
if (!internal) { | ||
throw new TypeError("next() called on a value that is not an iterator prototype object"); | ||
throw new globalObject.TypeError("next() called on a value that is not a ${this.name} iterator object"); | ||
} | ||
@@ -549,3 +547,3 @@ | ||
if (index >= len) { | ||
return { value: undefined, done: true }; | ||
return newObjectInRealm(globalObject, { value: undefined, done: true }); | ||
} | ||
@@ -555,13 +553,6 @@ | ||
internal.index = index + 1; | ||
return utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind); | ||
}, | ||
writable: true, | ||
enumerable: true, | ||
configurable: true | ||
}, | ||
[Symbol.toStringTag]: { | ||
value: "${this.name} Iterator", | ||
configurable: true | ||
return newObjectInRealm(globalObject, utils.iteratorResult(pair.map(utils.tryWrapperForImpl), kind)); | ||
} | ||
} | ||
}); | ||
); | ||
`; | ||
@@ -635,7 +626,7 @@ } | ||
}; | ||
exports.convert = (value, { context = "The provided value" } = {}) => { | ||
exports.convert = (globalObject, value, { context = "The provided value" } = {}) => { | ||
if (exports.is(value)) { | ||
return utils.implForWrapper(value); | ||
} | ||
throw new TypeError(\`\${context} is not of type '${this.name}'.\`); | ||
throw new globalObject.TypeError(\`\${context} is not of type '${this.name}'.\`); | ||
}; | ||
@@ -647,4 +638,6 @@ `; | ||
this.str += ` | ||
exports.createDefaultAsyncIterator = (target, kind) => { | ||
const iterator = Object.create(AsyncIteratorPrototype); | ||
exports.createDefaultAsyncIterator = (globalObject, target, kind) => { | ||
const ctorRegistry = globalObject[ctorRegistrySymbol]; | ||
const asyncIteratorPrototype = ctorRegistry["${this.name} AsyncIterator"]; | ||
const iterator = Object.create(asyncIteratorPrototype); | ||
Object.defineProperty(iterator, utils.iterInternalSymbol, { | ||
@@ -659,4 +652,6 @@ value: { target, kind, ongoingPromise: null, isFinished: false }, | ||
this.str += ` | ||
exports.createDefaultIterator = (target, kind) => { | ||
const iterator = Object.create(IteratorPrototype); | ||
exports.createDefaultIterator = (globalObject, target, kind) => { | ||
const ctorRegistry = globalObject[ctorRegistrySymbol]; | ||
const iteratorPrototype = ctorRegistry["${this.name} Iterator"]; | ||
const iterator = Object.create(iteratorPrototype); | ||
Object.defineProperty(iterator, utils.iterInternalSymbol, { | ||
@@ -725,4 +720,9 @@ value: { target, kind, index: 0 }, | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "indexedValue", arg.idlType, arg.extAttrs, this.name, | ||
`"Failed to set the " + index + " property on '${this.name}': The provided value"`); | ||
this.ctx, | ||
"indexedValue", | ||
arg.idlType, | ||
arg.extAttrs, | ||
this.name, | ||
`"Failed to set the " + index + " property on '${this.name}': The provided value"` | ||
); | ||
this.requires.merge(conv.requires); | ||
@@ -765,4 +765,9 @@ | ||
const conv = Types.generateTypeConversion( | ||
this.ctx, "namedValue", arg.idlType, arg.extAttrs, this.name, | ||
`"Failed to set the '" + ${P} + "' property on '${this.name}': The provided value"`); | ||
this.ctx, | ||
"namedValue", | ||
arg.idlType, | ||
arg.extAttrs, | ||
this.name, | ||
`"Failed to set the '" + ${P} + "' property on '${this.name}': The provided value"` | ||
); | ||
this.requires.merge(conv.requires); | ||
@@ -800,17 +805,9 @@ | ||
let sep = ""; | ||
if (this.needsPerGlobalProxyHandler) { | ||
this.str += ` | ||
const proxyHandlerCache = new WeakMap(); | ||
class ProxyHandler { | ||
constructor(globalObject) { | ||
this._globalObject = globalObject; | ||
} | ||
`; | ||
} else { | ||
this.str += ` | ||
const proxyHandler = { | ||
`; | ||
sep = ","; | ||
} | ||
this.str += ` | ||
const proxyHandlerCache = new WeakMap(); | ||
class ProxyHandler { | ||
constructor(globalObject) { | ||
this._globalObject = globalObject; | ||
} | ||
`; | ||
@@ -839,3 +836,3 @@ // [[Get]] (necessary because of proxy semantics) | ||
return Reflect.apply(getter, receiver, []); | ||
}${sep} | ||
} | ||
`; | ||
@@ -858,3 +855,3 @@ | ||
return false; | ||
}${sep} | ||
} | ||
`; | ||
@@ -890,3 +887,3 @@ | ||
return [...keys]; | ||
}${sep} | ||
} | ||
`; | ||
@@ -965,3 +962,3 @@ | ||
return Reflect.getOwnPropertyDescriptor(target, P); | ||
}${sep} | ||
} | ||
`; | ||
@@ -980,7 +977,5 @@ | ||
if (this.needsPerGlobalProxyHandler) { | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
} | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
@@ -1069,3 +1064,3 @@ if (this.supportsIndexedProperties && hasIndexedSetter) { | ||
return Reflect.defineProperty(receiver, P, valueDesc); | ||
}${sep} | ||
} | ||
`; | ||
@@ -1081,7 +1076,5 @@ | ||
if (this.needsPerGlobalProxyHandler) { | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
} | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
@@ -1166,3 +1159,3 @@ if (this.supportsIndexedProperties) { | ||
this.str += ` | ||
}${sep} | ||
} | ||
`; | ||
@@ -1178,7 +1171,5 @@ | ||
if (this.needsPerGlobalProxyHandler) { | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
} | ||
this.str += ` | ||
const globalObject = this._globalObject; | ||
`; | ||
@@ -1230,3 +1221,3 @@ if (this.supportsIndexedProperties) { | ||
return Reflect.deleteProperty(target, P); | ||
}${sep} | ||
} | ||
`; | ||
@@ -1247,14 +1238,16 @@ | ||
generateIface() { | ||
const { _needsUnforgeablesObject } = this; | ||
this.str += ` | ||
function makeWrapper(globalObject) { | ||
if (globalObject[ctorRegistrySymbol] === undefined) { | ||
throw new Error('Internal error: invalid global object'); | ||
function makeWrapper(globalObject, newTarget) { | ||
let proto; | ||
if (newTarget !== undefined) { | ||
proto = newTarget.prototype; | ||
} | ||
const ctor = globalObject[ctorRegistrySymbol]["${this.name}"]; | ||
if (ctor === undefined) { | ||
throw new Error('Internal error: constructor ${this.name} is not installed on the passed global object'); | ||
if (!utils.isObject(proto)) { | ||
proto = globalObject[ctorRegistrySymbol]["${this.name}"].prototype; | ||
} | ||
return Object.create(ctor.prototype); | ||
return Object.create(proto); | ||
} | ||
@@ -1265,20 +1258,15 @@ `; | ||
if (this.isLegacyPlatformObj) { | ||
setWrapperToProxy = ` | ||
wrapper = new Proxy(wrapper, proxyHandler);`; | ||
if (this.needsPerGlobalProxyHandler) { | ||
this.str += ` | ||
function makeProxy(wrapper, globalObject) { | ||
let proxyHandler = proxyHandlerCache.get(globalObject); | ||
if (proxyHandler === undefined) { | ||
proxyHandler = new ProxyHandler(globalObject); | ||
proxyHandlerCache.set(globalObject, proxyHandler); | ||
} | ||
return new Proxy(wrapper, proxyHandler); | ||
this.str += ` | ||
function makeProxy(wrapper, globalObject) { | ||
let proxyHandler = proxyHandlerCache.get(globalObject); | ||
if (proxyHandler === undefined) { | ||
proxyHandler = new ProxyHandler(globalObject); | ||
proxyHandlerCache.set(globalObject, proxyHandler); | ||
} | ||
`; | ||
return new Proxy(wrapper, proxyHandler); | ||
} | ||
`; | ||
setWrapperToProxy = ` | ||
wrapper = makeProxy(wrapper, globalObject);`; | ||
} | ||
setWrapperToProxy = ` | ||
wrapper = makeProxy(wrapper, globalObject);`; | ||
} | ||
@@ -1296,3 +1284,9 @@ | ||
}; | ||
`; | ||
if (_needsUnforgeablesObject) { | ||
this.generateUnforgeablesObject(); | ||
} | ||
this.str += ` | ||
exports._internalSetup = (wrapper, globalObject) => { | ||
@@ -1307,2 +1301,8 @@ `; | ||
if (_needsUnforgeablesObject) { | ||
this.str += ` | ||
utils.define(wrapper, getUnforgeables(globalObject)); | ||
`; | ||
} | ||
this.generateOnInstance(); | ||
@@ -1330,4 +1330,4 @@ | ||
exports.new = globalObject => { | ||
${this.isLegacyPlatformObj ? "let" : "const"} wrapper = makeWrapper(globalObject); | ||
exports.new = (globalObject, newTarget) => { | ||
${this.isLegacyPlatformObj ? "let" : "const"} wrapper = makeWrapper(globalObject, newTarget); | ||
@@ -1366,3 +1366,8 @@ exports._internalSetup(wrapper, globalObject); | ||
const conversions = Parameters.generateOverloadConversions( | ||
this.ctx, "constructor", this.name, this, `Failed to construct '${this.name}': `); | ||
this.ctx, | ||
"constructor", | ||
this.name, | ||
this, | ||
`Failed to construct '${this.name}': ` | ||
); | ||
this.requires.merge(conversions.requires); | ||
@@ -1382,3 +1387,3 @@ | ||
body = ` | ||
throw new TypeError("Illegal constructor"); | ||
throw new globalObject.TypeError("Illegal constructor"); | ||
`; | ||
@@ -1405,3 +1410,3 @@ } | ||
if (this.supportsIndexedProperties) { | ||
this.addProperty(this.defaultWhence, Symbol.iterator, "Array.prototype[Symbol.iterator]"); | ||
this.addProperty(this.defaultWhence, Symbol.iterator, "globalObject.Array.prototype[Symbol.iterator]"); | ||
} | ||
@@ -1541,2 +1546,3 @@ } | ||
generateOnInstance() { | ||
const { isGlobal } = this; | ||
const methods = []; | ||
@@ -1552,3 +1558,3 @@ const props = new Map(); | ||
for (const [name, { whence, type, args, body, descriptor }] of this._outputMethods) { | ||
if (whence !== "instance") { | ||
if (whence !== "instance" && (whence !== "unforgeables" || !isGlobal)) { | ||
continue; | ||
@@ -1595,6 +1601,5 @@ } | ||
this.str += ` | ||
Object.defineProperties( | ||
wrapper, | ||
Object.getOwnPropertyDescriptors({ ${methods.join(", ")} }) | ||
); | ||
utils.define(wrapper, { | ||
${methods.join(", ")} | ||
}); | ||
`; | ||
@@ -1612,5 +1617,71 @@ } | ||
generateUnforgeablesObject() { | ||
const methods = []; | ||
const props = new Map(); | ||
function addOne(name, args, body) { | ||
methods.push(` | ||
${name}(${utils.formatArgs(args)}) {${body}} | ||
`); | ||
} | ||
for (const [name, { whence, type, args, body, descriptor }] of this._outputMethods) { | ||
if (whence !== "unforgeables") { | ||
continue; | ||
} | ||
const propName = utils.stringifyPropertyKey(name); | ||
if (type === "regular") { | ||
addOne(propName, args, body); | ||
} else { | ||
if (body[0] !== undefined) { | ||
addOne(`get ${propName}`, [], body[0]); | ||
} | ||
if (body[1] !== undefined) { | ||
addOne(`set ${propName}`, args, body[1]); | ||
} | ||
} | ||
const descriptorModifier = utils.getPropertyDescriptorModifier(defaultObjectLiteralDescriptor, descriptor, type); | ||
if (descriptorModifier === undefined) { | ||
continue; | ||
} | ||
props.set(utils.stringifyPropertyKey(name), descriptorModifier); | ||
} | ||
this.str += ` | ||
function getUnforgeables(globalObject) { | ||
let unforgeables = unforgeablesMap.get(globalObject); | ||
if (unforgeables === undefined) { | ||
unforgeables = Object.create(null); | ||
`; | ||
if (methods.length > 0) { | ||
this.str += `utils.define(unforgeables, { ${methods.join(", ")} });`; | ||
} | ||
if (props.size > 0) { | ||
const propStrs = [...props].map(([name, body]) => `${name}: ${body}`); | ||
this.str += ` | ||
Object.defineProperties(unforgeables, { | ||
${propStrs.join(", ")} | ||
});`; | ||
} | ||
this.str += ` | ||
unforgeablesMap.set(globalObject, unforgeables); | ||
} | ||
return unforgeables; | ||
} | ||
`; | ||
} | ||
generateInstall() { | ||
const { idl, name } = this; | ||
if (this._needsUnforgeablesObject) { | ||
this.str += ` | ||
const unforgeablesMap = new WeakMap();`; | ||
} | ||
this.str += ` | ||
@@ -1623,12 +1694,6 @@ const exposed = new Set(${JSON.stringify([...this.exposed])}); | ||
} | ||
const ctorRegistry = utils.initCtorRegistry(globalObject); | ||
`; | ||
if (idl.inheritance) { | ||
this.str += ` | ||
if (globalObject.${idl.inheritance} === undefined) { | ||
throw new Error('Internal error: attempting to evaluate ${name} before ${idl.inheritance}'); | ||
} | ||
`; | ||
} | ||
const ext = idl.inheritance ? ` extends globalObject.${idl.inheritance}` : ""; | ||
@@ -1640,12 +1705,16 @@ | ||
const isLegacyNoInterfaceObject = Boolean(utils.getExtAttr(idl.extAttrs, "LegacyNoInterfaceObject")); | ||
if (isLegacyNoInterfaceObject) { | ||
this.str += `delete ${name}.constructor;`; | ||
} | ||
this.generateOffInstanceAfterClass(); | ||
this.str += ` | ||
if (globalObject[ctorRegistrySymbol] === undefined) { | ||
globalObject[ctorRegistrySymbol] = Object.create(null); | ||
} | ||
globalObject[ctorRegistrySymbol][interfaceName] = ${name}; | ||
ctorRegistry[interfaceName] = ${name}; | ||
`; | ||
if (!utils.getExtAttr(this.idl.extAttrs, "LegacyNoInterfaceObject")) { | ||
this.generateInstallIteratorPrototype(); | ||
if (!isLegacyNoInterfaceObject) { | ||
this.str += ` | ||
@@ -1689,3 +1758,2 @@ Object.defineProperty(globalObject, interfaceName, { | ||
`; | ||
this.generateIterator(); | ||
@@ -1695,2 +1763,3 @@ this.generateExport(); | ||
this.generateInstall(); | ||
if (this.isLegacyPlatformObj) { | ||
@@ -1697,0 +1766,0 @@ this.generateLegacyProxyHandler(); |
@@ -28,5 +28,5 @@ "use strict"; | ||
if (!exports.is(this)) { | ||
throw new TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
throw new globalObject.TypeError("'${key}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
} | ||
return exports.createDefaultIterator(this, "${kind}"); | ||
return exports.createDefaultIterator(globalObject, this, "${kind}"); | ||
`); | ||
@@ -46,9 +46,8 @@ } | ||
if (!exports.is(this)) { | ||
throw new TypeError("'forEach' called on an object that is not a valid instance of ${this.interface.name}."); | ||
throw new globalObject.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 globalObject.TypeError("Failed to execute 'forEach' on '${this.name}': 1 argument required, but only 0 present."); | ||
} | ||
callback = ${requires.addRelative("Function")}.convert(callback, { | ||
callback = ${requires.addRelative("Function")}.convert(globalObject, callback, { | ||
context: "Failed to execute 'forEach' on '${this.name}': The callback provided as parameter 1" | ||
@@ -67,6 +66,6 @@ }); | ||
} else { | ||
this.interface.addProperty(whence, "keys", "Array.prototype.keys"); | ||
this.interface.addProperty(whence, "values", "Array.prototype[Symbol.iterator]"); | ||
this.interface.addProperty(whence, "entries", "Array.prototype.entries"); | ||
this.interface.addProperty(whence, "forEach", "Array.prototype.forEach"); | ||
this.interface.addProperty(whence, "keys", "globalObject.Array.prototype.keys"); | ||
this.interface.addProperty(whence, "values", "globalObject.Array.prototype.values"); | ||
this.interface.addProperty(whence, "entries", "globalObject.Array.prototype.entries"); | ||
this.interface.addProperty(whence, "forEach", "globalObject.Array.prototype.forEach"); | ||
// @@iterator is added in Interface class. | ||
@@ -73,0 +72,0 @@ } |
@@ -18,6 +18,9 @@ "use strict"; | ||
isOnInstance() { | ||
const firstOverloadOnInstance = utils.isOnInstance(this.idls[0], this.interface.idl); | ||
for (const overload of this.idls.slice(1)) { | ||
if (utils.isOnInstance(overload, this.interface.idl) !== firstOverloadOnInstance) { | ||
getWhence() { | ||
const { idls } = this; | ||
const firstOverloadOnInstance = utils.isOnInstance(idls[0], this.interface.idl); | ||
const hasLegacyUnforgeable = Boolean(utils.getExtAttr(idls[0].extAttrs, "LegacyUnforgeable")); | ||
for (let i = 1; i < idls.length; i++) { | ||
if (Boolean(utils.getExtAttr(idls[i].extAttrs, "LegacyUnforgeable")) !== hasLegacyUnforgeable) { | ||
throw new Error( | ||
@@ -28,3 +31,8 @@ `[LegacyUnforgeable] is not applied uniformly to operation "${this.name}" on ${this.interface.name}` | ||
} | ||
return firstOverloadOnInstance; | ||
if (hasLegacyUnforgeable) { | ||
return "unforgeables"; | ||
} | ||
return firstOverloadOnInstance ? "instance" : "prototype"; | ||
} | ||
@@ -91,6 +99,6 @@ | ||
const onInstance = this.isOnInstance(); | ||
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 globalObject.Promise.reject(e); }` : ``; | ||
const hasCallWithGlobal = this.hasCallWithGlobal(); | ||
@@ -113,3 +121,3 @@ | ||
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 globalObject.TypeError("'${this.name}' called on an object that is not a valid instance of ${this.interface.name}."); | ||
} | ||
@@ -125,3 +133,8 @@ `; | ||
const parameterConversions = Parameters.generateOverloadConversions( | ||
this.ctx, type, this.name, this.interface, `Failed to execute '${this.name}' on '${this.interface.name}': `); | ||
this.ctx, | ||
type, | ||
this.name, | ||
this.interface, | ||
`Failed to execute '${this.name}' on '${this.interface.name}': ` | ||
); | ||
const args = []; | ||
@@ -162,5 +175,5 @@ requires.merge(parameterConversions.requires); | ||
} else { | ||
const forgeable = !utils.getExtAttr(this.idls[0].extAttrs, "LegacyUnforgeable"); | ||
const forgeable = whence !== "unforgeables"; | ||
this.interface.addMethod( | ||
onInstance ? "instance" : "prototype", | ||
whence, | ||
this.name, | ||
@@ -167,0 +180,0 @@ argNames, |
@@ -14,3 +14,3 @@ "use strict"; | ||
callback Function = any (any... arguments); | ||
callback VoidFunction = void (); | ||
callback VoidFunction = undefined (); | ||
`); | ||
@@ -17,0 +17,0 @@ |
"use strict"; | ||
/* eslint-disable array-element-newline */ | ||
module.exports = new Set([ | ||
@@ -12,2 +13,3 @@ "break", "case", "class", "catch", "const", "continue", "debugger", "default", "delete", | ||
"null", "true", "false"]); | ||
"null", "true", "false" | ||
]); |
@@ -5,3 +5,3 @@ "use strict"; | ||
function isObject(value) { | ||
return typeof value === "object" && value !== null || typeof value === "function"; | ||
return (typeof value === "object" && value !== null) || typeof value === "function"; | ||
} | ||
@@ -11,7 +11,57 @@ | ||
// Like `Object.assign`, but using `[[GetOwnProperty]]` and `[[DefineOwnProperty]]` | ||
// instead of `[[Get]]` and `[[Set]]` and only allowing objects | ||
function define(target, source) { | ||
for (const key of Reflect.ownKeys(source)) { | ||
const descriptor = Reflect.getOwnPropertyDescriptor(source, key); | ||
if (descriptor && !Reflect.defineProperty(target, key, descriptor)) { | ||
throw new TypeError(`Cannot redefine property: ${String(key)}`); | ||
} | ||
} | ||
} | ||
function newObjectInRealm(globalObject, object) { | ||
const ctorRegistry = initCtorRegistry(globalObject); | ||
return Object.defineProperties( | ||
Object.create(ctorRegistry["%Object.prototype%"]), | ||
Object.getOwnPropertyDescriptors(object) | ||
); | ||
} | ||
const wrapperSymbol = Symbol("wrapper"); | ||
const implSymbol = Symbol("impl"); | ||
const sameObjectCaches = Symbol("SameObject caches"); | ||
const ctorRegistrySymbol = Symbol.for("[webidl2js] constructor registry"); | ||
const ctorRegistrySymbol = Symbol.for("[webidl2js] constructor registry"); | ||
const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype); | ||
function initCtorRegistry(globalObject) { | ||
if (hasOwn(globalObject, ctorRegistrySymbol)) { | ||
return globalObject[ctorRegistrySymbol]; | ||
} | ||
const ctorRegistry = Object.create(null); | ||
// In addition to registering all the WebIDL2JS-generated types in the constructor registry, | ||
// we also register a few intrinsics that we make use of in generated code, since they are not | ||
// easy to grab from the globalObject variable. | ||
ctorRegistry["%Object.prototype%"] = globalObject.Object.prototype; | ||
ctorRegistry["%IteratorPrototype%"] = Object.getPrototypeOf( | ||
Object.getPrototypeOf(new globalObject.Array()[Symbol.iterator]()) | ||
); | ||
try { | ||
ctorRegistry["%AsyncIteratorPrototype%"] = Object.getPrototypeOf( | ||
Object.getPrototypeOf( | ||
globalObject.eval("(async function* () {})").prototype | ||
) | ||
); | ||
} catch { | ||
ctorRegistry["%AsyncIteratorPrototype%"] = AsyncIteratorPrototype; | ||
} | ||
globalObject[ctorRegistrySymbol] = ctorRegistry; | ||
return ctorRegistry; | ||
} | ||
function getSameObject(wrapper, prop, creator) { | ||
@@ -49,4 +99,2 @@ if (!wrapper[sameObjectCaches]) { | ||
const iterInternalSymbol = Symbol("internal"); | ||
const IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); | ||
const AsyncIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf(async function* () {}).prototype); | ||
@@ -58,3 +106,3 @@ function isArrayIndexPropName(P) { | ||
const i = P >>> 0; | ||
if (i === Math.pow(2, 32) - 1) { | ||
if (i === 2 ** 32 - 1) { | ||
return false; | ||
@@ -116,2 +164,4 @@ } | ||
hasOwn, | ||
define, | ||
newObjectInRealm, | ||
wrapperSymbol, | ||
@@ -121,2 +171,3 @@ implSymbol, | ||
ctorRegistrySymbol, | ||
initCtorRegistry, | ||
wrapperForImpl, | ||
@@ -127,4 +178,2 @@ implForWrapper, | ||
iterInternalSymbol, | ||
IteratorPrototype, | ||
AsyncIteratorPrototype, | ||
isArrayBuffer, | ||
@@ -131,0 +180,0 @@ isArrayIndexPropName, |
@@ -10,3 +10,3 @@ "use strict"; | ||
parent = Types.resolveType(ctx, parent); | ||
return predicate(parent) || parent.union && parent.idlType.some(predicate); | ||
return predicate(parent) || (parent.union && parent.idlType.some(predicate)); | ||
} | ||
@@ -21,5 +21,4 @@ | ||
if (isDefaultedDictionary && !ctx.dictionaries.has(idlType.idlType)) { | ||
throw new Error( | ||
`The parameter ${overload.operation.arguments[i].name} was defaulted to {}, but no dictionary named ` + | ||
`${idlType.idlType} exists`); | ||
throw new Error(`The parameter ${overload.operation.arguments[i].name} was defaulted to {}, but no dictionary ` + | ||
`named ${idlType.idlType} exists`); | ||
} | ||
@@ -34,5 +33,5 @@ const optional = overload.optionalityList[i] === "optional" && !isDefaultedDictionary; | ||
const msg = typeof targetIdx === "string" ? | ||
`"${errPrefix}parameter " + (${targetIdx} + 1)` : `"${errPrefix}parameter ${i + 1}"`; | ||
const conv = Types.generateTypeConversion( | ||
ctx, "curArg", idlType, [], parent.name, msg); | ||
`"${errPrefix}parameter " + (${targetIdx} + 1)` : | ||
`"${errPrefix}parameter ${i + 1}"`; | ||
const conv = Types.generateTypeConversion(ctx, "curArg", idlType, [], parent.name, msg); | ||
requires.merge(conv.requires); | ||
@@ -71,4 +70,3 @@ str += conv.body; | ||
if (isDefaultedDictionary && !ctx.dictionaries.has(idlArg.idlType.idlType)) { | ||
throw new Error( | ||
`The dictionary ${idlArg.idlType.idlType} was referenced in an argument list, but doesn't exist`); | ||
throw new Error(`The dictionary ${idlArg.idlType.idlType} was referenced in an argument list, but doesn't exist`); | ||
} | ||
@@ -122,4 +120,3 @@ | ||
if (arguments.length < ${minArgs}) { | ||
throw new TypeError("${errPrefix}${minArgs} argument${plural} required, but only " + arguments.length + | ||
" present."); | ||
throw new globalObject.TypeError(\`${errPrefix}${minArgs} argument${plural} required, but only \${arguments.length} present.\`); | ||
} | ||
@@ -137,3 +134,3 @@ `; | ||
switchCases.push(` | ||
throw new TypeError("${errPrefix}only " + arguments.length + " arguments present."); | ||
throw new globalObject.TypeError(\`${errPrefix}only \${arguments.length} arguments present.\`); | ||
`); | ||
@@ -314,3 +311,3 @@ continue; | ||
} else { | ||
possibilities.push(`throw new TypeError("${errPrefix}No such overload");`); | ||
possibilities.push(`throw new globalObject.TypeError("${errPrefix}No such overload");`); | ||
} | ||
@@ -349,3 +346,3 @@ | ||
if (lastBody !== undefined && switchCases[i] !== lastBody) { | ||
str += lastBody + "break;"; | ||
str += `${lastBody}break;`; | ||
} | ||
@@ -356,3 +353,3 @@ str += `case ${minArgs + i}:`; | ||
if (lastBody !== undefined && switchCases[switchCases.length - 1] !== lastBody) { | ||
str += lastBody + "break;"; | ||
str += `${lastBody}break;`; | ||
} | ||
@@ -359,0 +356,0 @@ str += "default:"; |
@@ -149,3 +149,3 @@ "use strict"; | ||
if (!this.ctx.options.suppressErrors) { | ||
throw new Error("Can't convert type '" + instruction.type + "'"); | ||
throw new Error(`Can't convert type '${instruction.type}'`); | ||
} | ||
@@ -159,4 +159,3 @@ } | ||
for (const instruction of file.idl) { | ||
let oldMembers; | ||
let extAttrs; | ||
let oldMembers, extAttrs; | ||
switch (instruction.type) { | ||
@@ -220,3 +219,3 @@ case "interface": | ||
if (relativeUtils[0] !== ".") { | ||
relativeUtils = "./" + relativeUtils; | ||
relativeUtils = `./${relativeUtils}`; | ||
} | ||
@@ -230,3 +229,3 @@ | ||
if (implFile[0] !== ".") { | ||
implFile = "./" + implFile; | ||
implFile = `./${implFile}`; | ||
} | ||
@@ -245,3 +244,3 @@ | ||
await fs.writeFile(path.join(outputDir, obj.name + ".js"), source); | ||
await fs.writeFile(path.join(outputDir, `${obj.name}.js`), source); | ||
} | ||
@@ -262,3 +261,3 @@ | ||
await fs.writeFile(path.join(outputDir, obj.name + ".js"), source); | ||
await fs.writeFile(path.join(outputDir, `${obj.name}.js`), source); | ||
} | ||
@@ -272,3 +271,3 @@ | ||
`); | ||
await fs.writeFile(path.join(outputDir, obj.name + ".js"), source); | ||
await fs.writeFile(path.join(outputDir, `${obj.name}.js`), source); | ||
} | ||
@@ -275,0 +274,0 @@ } |
150
lib/types.js
@@ -8,4 +8,11 @@ "use strict"; | ||
const typedArrayTypes = new Set([ | ||
"Int8Array", "Int16Array", "Int32Array", "Uint8Array", "Uint16Array", "Uint32Array", | ||
"Uint8ClampedArray", "Float32Array", "Float64Array" | ||
"Int8Array", | ||
"Int16Array", | ||
"Int32Array", | ||
"Uint8Array", | ||
"Uint16Array", | ||
"Uint32Array", | ||
"Uint8ClampedArray", | ||
"Float32Array", | ||
"Float64Array" | ||
]); | ||
@@ -16,8 +23,12 @@ const arrayBufferViewTypes = new Set([...typedArrayTypes, "DataView"]); | ||
const integerTypes = new Set([ | ||
"byte", "octet", "short", "unsigned short", "long", "unsigned long", | ||
"long long", "unsigned long long" | ||
"byte", | ||
"octet", | ||
"short", | ||
"unsigned short", | ||
"long", | ||
"unsigned long", | ||
"long long", | ||
"unsigned long long" | ||
]); | ||
const numericTypes = new Set([ | ||
...integerTypes, "float", "unrestricted float", "double", "unrestricted double" | ||
]); | ||
const numericTypes = new Set([...integerTypes, "float", "unrestricted float", "double", "unrestricted double"]); | ||
@@ -88,3 +99,10 @@ const resolvedMap = new WeakMap(); | ||
function generateTypeConversion(ctx, name, idlType, argAttrs = [], parentName, errPrefix = '"The provided value"') { | ||
function generateTypeConversion( | ||
ctx, | ||
name, | ||
idlType, | ||
argAttrs = [], | ||
parentName = undefined, | ||
errPrefix = '"The provided value"' | ||
) { | ||
const requires = new utils.RequiresMap(ctx); | ||
@@ -128,10 +146,5 @@ let str = ""; | ||
generateFrozenArray(); | ||
} else if ( | ||
// TODO: Revert once `Function` and `VoidFunction` are removed from `webidl-conversions`: | ||
idlType.idlType !== "Function" && | ||
idlType.idlType !== "VoidFunction" && | ||
conversions[idlType.idlType] | ||
) { | ||
} else if (conversions[idlType.idlType]) { | ||
// string or number type compatible with webidl-conversions | ||
generateGeneric(`conversions["${idlType.idlType}"]`); | ||
generateWebIDLConversions(`conversions["${idlType.idlType}"]`); | ||
} else if (resolvedTypes.has(ctx.typeOf(idlType.idlType))) { | ||
@@ -147,3 +160,3 @@ // callback functions, callback interfaces, dictionaries, enumerations, and interfaces | ||
} | ||
generateGeneric(fn); | ||
generateWebIDL2JS(fn); | ||
} else { | ||
@@ -227,4 +240,10 @@ // unknown | ||
if (union.callbackFunction) { | ||
const conv = generateTypeConversion(ctx, name, union.callbackFunction, [], parentName, | ||
`${errPrefix} + " callback function"`); | ||
const conv = generateTypeConversion( | ||
ctx, | ||
name, | ||
union.callbackFunction, | ||
[], | ||
parentName, | ||
`${errPrefix} + " callback function"` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -246,4 +265,10 @@ code += conv.body; | ||
code += `if (${name}[Symbol.iterator] !== undefined) {`; | ||
const conv = generateTypeConversion(ctx, name, union.sequenceLike, [], parentName, | ||
`${errPrefix} + " sequence"`); | ||
const conv = generateTypeConversion( | ||
ctx, | ||
name, | ||
union.sequenceLike, | ||
[], | ||
parentName, | ||
`${errPrefix} + " sequence"` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -255,14 +280,25 @@ code += conv.body; | ||
if (union.dictionary) { | ||
const conv = generateTypeConversion(ctx, name, union.dictionary, [], parentName, | ||
`${errPrefix} + " dictionary"`); | ||
const conv = generateTypeConversion( | ||
ctx, | ||
name, | ||
union.dictionary, | ||
[], | ||
parentName, | ||
`${errPrefix} + " dictionary"` | ||
); | ||
requires.merge(conv.requires); | ||
code += conv.body; | ||
} else if (union.record) { | ||
const conv = generateTypeConversion(ctx, name, union.record, [], parentName, | ||
`${errPrefix} + " record"`); | ||
const conv = generateTypeConversion(ctx, name, union.record, [], parentName, `${errPrefix} + " record"`); | ||
requires.merge(conv.requires); | ||
code += conv.body; | ||
} else if (union.callbackInterface) { | ||
const conv = generateTypeConversion(ctx, name, union.callbackInterface, [], parentName, | ||
`${errPrefix} + " callback interface"`); | ||
const conv = generateTypeConversion( | ||
ctx, | ||
name, | ||
union.callbackInterface, | ||
[], | ||
parentName, | ||
`${errPrefix} + " callback interface"` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -307,3 +343,3 @@ code += conv.body; | ||
} else { | ||
code += `throw new TypeError(${errPrefix} + " is not of any supported type.")`; | ||
code += `throw new globalObject.TypeError(${errPrefix} + " is not of any supported type.")`; | ||
} | ||
@@ -318,4 +354,10 @@ code += "}"; | ||
function generateSequence() { | ||
const conv = generateTypeConversion(ctx, "nextItem", idlType.idlType[0], [], parentName, | ||
`${errPrefix} + "'s element"`); | ||
const conv = generateTypeConversion( | ||
ctx, | ||
"nextItem", | ||
idlType.idlType[0], | ||
[], | ||
parentName, | ||
`${errPrefix} + "'s element"` | ||
); | ||
requires.merge(conv.requires); | ||
@@ -325,3 +367,3 @@ | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an iterable object."); | ||
throw new globalObject.TypeError(${errPrefix} + " is not an iterable object."); | ||
} else { | ||
@@ -340,7 +382,19 @@ const V = []; | ||
function generateRecord() { | ||
const keyConv = generateTypeConversion(ctx, "typedKey", idlType.idlType[0], [], parentName, | ||
`${errPrefix} + "'s key"`); | ||
const keyConv = generateTypeConversion( | ||
ctx, | ||
"typedKey", | ||
idlType.idlType[0], | ||
[], | ||
parentName, | ||
`${errPrefix} + "'s key"` | ||
); | ||
requires.merge(keyConv.requires); | ||
const valConv = generateTypeConversion(ctx, "typedValue", idlType.idlType[1], [], parentName, | ||
`${errPrefix} + "'s value"`); | ||
const valConv = generateTypeConversion( | ||
ctx, | ||
"typedValue", | ||
idlType.idlType[1], | ||
[], | ||
parentName, | ||
`${errPrefix} + "'s value"` | ||
); | ||
requires.merge(valConv.requires); | ||
@@ -350,3 +404,3 @@ | ||
if (!utils.isObject(${name})) { | ||
throw new TypeError(${errPrefix} + " is not an object."); | ||
throw new globalObject.TypeError(${errPrefix} + " is not an object."); | ||
} else { | ||
@@ -371,3 +425,3 @@ const result = Object.create(null); | ||
function generatePromise() { | ||
str += `${name} = new Promise(resolve => resolve(${name}));`; | ||
str += `${name} = new globalObject.Promise(resolve => resolve(${name}));`; | ||
} | ||
@@ -380,3 +434,3 @@ | ||
function generateGeneric(conversionFn) { | ||
function generateWebIDLConversions(conversionFn) { | ||
const enforceRange = utils.getExtAttr(extAttrs, "EnforceRange"); | ||
@@ -386,3 +440,3 @@ const clamp = utils.getExtAttr(extAttrs, "Clamp"); | ||
let optString = `context: ${errPrefix},`; | ||
let optString = `context: ${errPrefix}, globals: globalObject,`; | ||
if (clamp) { | ||
@@ -409,2 +463,18 @@ optString += "clamp: true,"; | ||
} | ||
function generateWebIDL2JS(conversionFn) { | ||
const optString = `context: ${errPrefix}`; | ||
if (idlType.array) { | ||
str += ` | ||
for (let i = 0; i < ${name}.length; ++i) { | ||
${name}[i] = ${conversionFn}(globalObject, ${name}[i], { ${optString} }); | ||
} | ||
`; | ||
} else { | ||
str += ` | ||
${name} = ${conversionFn}(globalObject, ${name}, { ${optString} }); | ||
`; | ||
} | ||
} | ||
} | ||
@@ -635,4 +705,4 @@ | ||
const effectivelyNullable2 = includesNullableType(ctx, resolved2) || includesDictionaryType(ctx, resolved2); | ||
if (includesNullableType(ctx, resolved1) && effectivelyNullable2 || | ||
effectivelyNullable1 && includesNullableType(ctx, resolved2)) { | ||
if ((includesNullableType(ctx, resolved1) && effectivelyNullable2) || | ||
(effectivelyNullable1 && includesNullableType(ctx, resolved2))) { | ||
return false; | ||
@@ -639,0 +709,0 @@ } |
@@ -20,3 +20,3 @@ "use strict"; | ||
} | ||
throw new Error("Unexpected default type: " + dflt.type); | ||
throw new Error(`Unexpected default type: ${dflt.type}`); | ||
} | ||
@@ -43,4 +43,3 @@ | ||
function isOnInstance(memberIDL, interfaceIDL) { | ||
return memberIDL.special !== "static" && (getExtAttr(memberIDL.extAttrs, "LegacyUnforgeable") || | ||
isGlobal(interfaceIDL)); | ||
return memberIDL.special !== "static" && isGlobal(interfaceIDL); | ||
} | ||
@@ -47,0 +46,0 @@ |
{ | ||
"name": "webidl2js", | ||
"version": "16.2.0", | ||
"version": "17.0.0", | ||
"description": "Auto-generates class structures for WebIDL specifications", | ||
"main": "lib/transformer.js", | ||
"files": [ | ||
"lib/" | ||
], | ||
"repository": "github:jsdom/webidl2js", | ||
"dependencies": { | ||
"prettier": "^2.0.4", | ||
"webidl-conversions": "^6.1.0", | ||
"webidl2": "^23.12.1" | ||
"prettier": "^2.4.1", | ||
"webidl-conversions": "^7.0.0", | ||
"webidl2": "^24.1.2" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^6.8.0", | ||
"jest": "^25.3.0" | ||
"@domenic/eslint-config": "^1.4.0", | ||
"eslint": "^7.32.0", | ||
"jest": "^27.2.4" | ||
}, | ||
@@ -28,3 +32,3 @@ "scripts": { | ||
"engines": { | ||
"node": ">=10" | ||
"node": ">=12" | ||
}, | ||
@@ -31,0 +35,0 @@ "author": "Sebastian Mayr <npm@smayr.name>", |
@@ -261,3 +261,3 @@ # JavaScript bindings generator for Web IDL | ||
#### `convert(value, { context })` | ||
#### `convert(globalObject, value, { context })` | ||
@@ -286,7 +286,7 @@ Performs the Web IDL conversion algorithm for this interface, converting _value_ into the correct representation of the interface type suitable for consumption by implementation classes: the corresponding impl. | ||
#### `new(globalObject)` | ||
#### `new(globalObject, newTarget)` | ||
Creates a new instance of the wrapper class and corresponding implementation class, but without invoking the implementation class constructor logic. Then returns the implementation class. | ||
This corresponds to the [Web IDL "new" algorithm](https://heycam.github.io/webidl/#new), and is useful when implementing specifications that initialize objects in different ways than their constructors do. | ||
This corresponds to the [WebIDL "create a new object implementing the interface"](https://heycam.github.io/webidl/#new) and ["internally create a new object implementing the interface"](https://heycam.github.io/webidl/#internally-create-a-new-object-implementing-the-interface) algorithms, and is useful when implementing specifications that initialize objects in different ways than their constructors do. | ||
@@ -301,9 +301,9 @@ #### `setup(obj, globalObject, constructorArgs, privateData)` | ||
#### `convert(value, { context })` | ||
#### `convert(globalObject, value, { context })` | ||
Performs the Web IDL conversion algorithm for this callback interface, converting _value_ into a function that performs [call a user object's operation](https://heycam.github.io/webidl/#call-a-user-objects-operation) when called, with _thisArg_ being the `this` value of the converted function. | ||
Performs the Web IDL conversion algorithm for this callback interface, converting `value` into a function that performs [call a user object's operation](https://heycam.github.io/webidl/#call-a-user-objects-operation) when called, with _thisArg_ being the `this` value of the converted function. `globalObject` is used to ensure error cases result in `Error` or `Promise` objects from the correct realm. | ||
The resulting function has an _objectReference_ property, which is the same object as _value_ and can be used to perform identity checks, as `convert` returns a new function object every time. | ||
The resulting function has an `objectReference` property, which is the same object as `value` and can be used to perform identity checks, as `convert` returns a new function object every time. | ||
If any part of the conversion fails, _context_ can be used to describe the provided value in any resulting error message. | ||
If any part of the conversion fails, `context` can be used to describe the provided value in any resulting error message. | ||
@@ -318,7 +318,7 @@ #### `install(globalObject, globalNames)` | ||
#### `convert(value, { context })` | ||
#### `convert(globalObject, value, { context })` | ||
Performs the Web IDL conversion algorithm for this dictionary, converting _value_ into the correct representation of the dictionary type suitable for consumption by implementation classes: a `null`-[[Prototype]] object with its properties properly converted. | ||
Performs the Web IDL conversion algorithm for this dictionary, converting `value` into the correct representation of the dictionary type suitable for consumption by implementation classes: a `null`-[[Prototype]] object with its properties properly converted. `globalObject` is used to ensure error cases result in `Error` or `Promise` objects from the correct realm. | ||
If any part of the conversion fails, _context_ can be used to describe the provided value in any resulting error message. | ||
If any part of the conversion fails, `context` can be used to describe the provided value in any resulting error message. | ||
@@ -538,3 +538,3 @@ ### Other requirements | ||
This extended attribute can be applied to named or indexed getters or setters. It says that whether the interface supports a given property name/index can be automatically derived by looking at the return value of its indexed getter/setter: whenever `value` is returned, the name/index is unsupported. Typically, `value` is either `undefined` or `_null`. | ||
This extended attribute can be applied to named or indexed getters or setters. It says that whether the interface supports a given property name/index can be automatically derived by looking at the return value of its indexed getter/setter: whenever `value` is returned, the name/index is unsupported. Typically, `value` is either `_undefined` or `_null`. | ||
@@ -541,0 +541,0 @@ In practice, this means that the implementation class only needs to implement a single method (the named/indexed getter method), and doesn't need to implement the `[idlUtils.supportsPropertyName]()` or `[idlUtils.supportsPropertyIndex]()` method separately. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
187480
4377
3
+ Addedwebidl-conversions@7.0.0(transitive)
+ Addedwebidl2@24.4.1(transitive)
- Removedwebidl-conversions@6.1.0(transitive)
- Removedwebidl2@23.13.1(transitive)
Updatedprettier@^2.4.1
Updatedwebidl-conversions@^7.0.0
Updatedwebidl2@^24.1.2