Skip to content

Commit ee7f6ef

Browse files
committed
Fix legacy factory functions for non‑default new.target values
1 parent 3a3baac commit ee7f6ef

File tree

3 files changed

+1188
-568
lines changed

3 files changed

+1188
-568
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,11 @@ Creates a new instance of the wrapper class and corresponding implementation cla
282282

283283
This is useful inside implementation class files, where it is easiest to only deal with impls, not wrappers.
284284

285-
#### `new(globalObject)`
285+
#### `new(globalObject [ , newTarget ])`
286286

287287
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.
288288

289-
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.
289+
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.
290290

291291
#### `setup(obj, globalObject, constructorArgs, privateData)`
292292

lib/constructs/interface.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class LegacyFactoryFunction {
8181
// This implements the WebIDL legacy factory function behavior, as well as support for overridding
8282
// the return type, which is used by HTML's element legacy factory functions:
8383
str += `
84-
const thisArgument = exports.new(globalObject);
84+
const thisArgument = exports.new(globalObject, new.target);
8585
const result = Impl.legacyFactoryFunction.call(thisArg, ${formatArgs(setupArgs)});
8686
return utils.tryWrapperForImpl(utils.isObject(result) ? result : thisArgument);
8787
`;
@@ -1206,17 +1206,25 @@ class Interface {
12061206

12071207
generateIface() {
12081208
this.str += `
1209-
function makeWrapper(globalObject) {
1209+
function makeWrapper(globalObject, newTarget = undefined) {
12101210
if (globalObject[ctorRegistrySymbol] === undefined) {
12111211
throw new Error('Internal error: invalid global object');
12121212
}
12131213
1214-
const ctor = globalObject[ctorRegistrySymbol]["${this.name}"];
1215-
if (ctor === undefined) {
1216-
throw new Error('Internal error: constructor ${this.name} is not installed on the passed global object');
1214+
let prototype;
1215+
if (newTarget !== undefined) {
1216+
({ prototype } = newTarget);
12171217
}
12181218
1219-
return Object.create(ctor.prototype);
1219+
if (!utils.isObject(prototype)) {
1220+
const ctor = globalObject[ctorRegistrySymbol]["${this.name}"];
1221+
if (ctor === undefined) {
1222+
throw new Error('Internal error: constructor ${this.name} is not installed on the passed global object');
1223+
}
1224+
({ prototype } = ctor);
1225+
}
1226+
1227+
return Object.create(prototype);
12201228
}
12211229
`;
12221230

@@ -1284,8 +1292,8 @@ class Interface {
12841292
return wrapper;
12851293
};
12861294
1287-
exports.new = globalObject => {
1288-
${this.isLegacyPlatformObj ? "let" : "const"} wrapper = makeWrapper(globalObject);
1295+
exports.new = (globalObject, newTarget = undefined) => {
1296+
${this.isLegacyPlatformObj ? "let" : "const"} wrapper = makeWrapper(globalObject, newTarget);
12891297
12901298
exports._internalSetup(wrapper, globalObject);
12911299
Object.defineProperty(wrapper, implSymbol, {

0 commit comments

Comments
 (0)