Skip to content

Commit

Permalink
Require [Exposed] even when marked as [LegacyNoInterfaceObject]
Browse files Browse the repository at this point in the history
  • Loading branch information
ExE-Boss authored and domenic committed Mar 7, 2021
1 parent 98d0aa4 commit aedda9b
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 14 deletions.
29 changes: 15 additions & 14 deletions lib/constructs/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,18 @@ class Interface {
}

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));
}

const legacyWindowAlias = utils.getExtAttr(this.idl.extAttrs, "LegacyWindowAlias");
Expand Down Expand Up @@ -1581,6 +1577,11 @@ class Interface {
this.generateOffInstanceMethods();
this.str += "}";

const isLegacyNoInterfaceObject = Boolean(utils.getExtAttr(idl.extAttrs, "LegacyNoInterfaceObject"));
if (isLegacyNoInterfaceObject) {
this.str += `delete ${name}.constructor;`;
}

this.generateOffInstanceAfterClass();

this.str += `
Expand All @@ -1590,7 +1591,7 @@ class Interface {
globalObject[ctorRegistrySymbol][interfaceName] = ${name};
`;

if (!utils.getExtAttr(this.idl.extAttrs, "LegacyNoInterfaceObject")) {
if (!isLegacyNoInterfaceObject) {
this.str += `
Object.defineProperty(globalObject, interfaceName, {
configurable: true,
Expand Down
282 changes: 282 additions & 0 deletions test/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3618,6 +3618,147 @@ const Impl = require(\\"../implementations/LegacyLenientAttributes.js\\");
"
`;

exports[`generation with processors LegacyNoInterfaceObject.webidl 1`] = `
"\\"use strict\\";

const conversions = require(\\"webidl-conversions\\");
const utils = require(\\"./utils.js\\");

const implSymbol = utils.implSymbol;
const ctorRegistrySymbol = utils.ctorRegistrySymbol;

const interfaceName = \\"LegacyNoInterfaceObject\\";

exports.is = value => {
return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
};
exports.isImpl = value => {
return utils.isObject(value) && value instanceof Impl.implementation;
};
exports.convert = (value, { context = \\"The provided value\\" } = {}) => {
if (exports.is(value)) {
return utils.implForWrapper(value);
}
throw new TypeError(\`\${context} is not of type 'LegacyNoInterfaceObject'.\`);
};

function makeWrapper(globalObject) {
if (globalObject[ctorRegistrySymbol] === undefined) {
throw new Error(\\"Internal error: invalid global object\\");
}

const ctor = globalObject[ctorRegistrySymbol][\\"LegacyNoInterfaceObject\\"];
if (ctor === undefined) {
throw new Error(\\"Internal error: constructor LegacyNoInterfaceObject is not installed on the passed global object\\");
}

return Object.create(ctor.prototype);
}

exports.create = (globalObject, constructorArgs, privateData) => {
const wrapper = makeWrapper(globalObject);
return exports.setup(wrapper, globalObject, constructorArgs, privateData);
};

exports.createImpl = (globalObject, constructorArgs, privateData) => {
const wrapper = exports.create(globalObject, constructorArgs, privateData);
return utils.implForWrapper(wrapper);
};

exports._internalSetup = (wrapper, globalObject) => {};

exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
privateData.wrapper = wrapper;

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: new Impl.implementation(globalObject, constructorArgs, privateData),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper;
};

exports.new = globalObject => {
const wrapper = makeWrapper(globalObject);

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: Object.create(Impl.implementation.prototype),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper[implSymbol];
};

const exposed = new Set([\\"Window\\"]);

exports.install = (globalObject, globalNames) => {
if (!globalNames.some(globalName => exposed.has(globalName))) {
return;
}
class LegacyNoInterfaceObject {
constructor() {
throw new TypeError(\\"Illegal constructor\\");
}

def() {
const esValue = this !== null && this !== undefined ? this : globalObject;
if (!exports.is(esValue)) {
throw new TypeError(\\"'def' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

return esValue[implSymbol].def();
}

get abc() {
const esValue = this !== null && this !== undefined ? this : globalObject;

if (!exports.is(esValue)) {
throw new TypeError(\\"'get abc' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

return esValue[implSymbol][\\"abc\\"];
}

set abc(V) {
const esValue = this !== null && this !== undefined ? this : globalObject;

if (!exports.is(esValue)) {
throw new TypeError(\\"'set abc' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

V = conversions[\\"DOMString\\"](V, {
context: \\"Failed to set the 'abc' property on 'LegacyNoInterfaceObject': The provided value\\"
});

esValue[implSymbol][\\"abc\\"] = V;
}
}
delete LegacyNoInterfaceObject.constructor;
Object.defineProperties(LegacyNoInterfaceObject.prototype, {
def: { enumerable: true },
abc: { enumerable: true },
[Symbol.toStringTag]: { value: \\"LegacyNoInterfaceObject\\", configurable: true }
});
if (globalObject[ctorRegistrySymbol] === undefined) {
globalObject[ctorRegistrySymbol] = Object.create(null);
}
globalObject[ctorRegistrySymbol][interfaceName] = LegacyNoInterfaceObject;
};

const Impl = require(\\"../implementations/LegacyNoInterfaceObject.js\\");
"
`;

exports[`generation with processors LegacyUnforgeable.webidl 1`] = `
"\\"use strict\\";

Expand Down Expand Up @@ -13729,6 +13870,147 @@ const Impl = require(\\"../implementations/LegacyLenientAttributes.js\\");
"
`;

exports[`generation without processors LegacyNoInterfaceObject.webidl 1`] = `
"\\"use strict\\";

const conversions = require(\\"webidl-conversions\\");
const utils = require(\\"./utils.js\\");

const implSymbol = utils.implSymbol;
const ctorRegistrySymbol = utils.ctorRegistrySymbol;

const interfaceName = \\"LegacyNoInterfaceObject\\";

exports.is = value => {
return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation;
};
exports.isImpl = value => {
return utils.isObject(value) && value instanceof Impl.implementation;
};
exports.convert = (value, { context = \\"The provided value\\" } = {}) => {
if (exports.is(value)) {
return utils.implForWrapper(value);
}
throw new TypeError(\`\${context} is not of type 'LegacyNoInterfaceObject'.\`);
};

function makeWrapper(globalObject) {
if (globalObject[ctorRegistrySymbol] === undefined) {
throw new Error(\\"Internal error: invalid global object\\");
}

const ctor = globalObject[ctorRegistrySymbol][\\"LegacyNoInterfaceObject\\"];
if (ctor === undefined) {
throw new Error(\\"Internal error: constructor LegacyNoInterfaceObject is not installed on the passed global object\\");
}

return Object.create(ctor.prototype);
}

exports.create = (globalObject, constructorArgs, privateData) => {
const wrapper = makeWrapper(globalObject);
return exports.setup(wrapper, globalObject, constructorArgs, privateData);
};

exports.createImpl = (globalObject, constructorArgs, privateData) => {
const wrapper = exports.create(globalObject, constructorArgs, privateData);
return utils.implForWrapper(wrapper);
};

exports._internalSetup = (wrapper, globalObject) => {};

exports.setup = (wrapper, globalObject, constructorArgs = [], privateData = {}) => {
privateData.wrapper = wrapper;

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: new Impl.implementation(globalObject, constructorArgs, privateData),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper;
};

exports.new = globalObject => {
const wrapper = makeWrapper(globalObject);

exports._internalSetup(wrapper, globalObject);
Object.defineProperty(wrapper, implSymbol, {
value: Object.create(Impl.implementation.prototype),
configurable: true
});

wrapper[implSymbol][utils.wrapperSymbol] = wrapper;
if (Impl.init) {
Impl.init(wrapper[implSymbol]);
}
return wrapper[implSymbol];
};

const exposed = new Set([\\"Window\\"]);

exports.install = (globalObject, globalNames) => {
if (!globalNames.some(globalName => exposed.has(globalName))) {
return;
}
class LegacyNoInterfaceObject {
constructor() {
throw new TypeError(\\"Illegal constructor\\");
}

def() {
const esValue = this !== null && this !== undefined ? this : globalObject;
if (!exports.is(esValue)) {
throw new TypeError(\\"'def' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

return esValue[implSymbol].def();
}

get abc() {
const esValue = this !== null && this !== undefined ? this : globalObject;

if (!exports.is(esValue)) {
throw new TypeError(\\"'get abc' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

return esValue[implSymbol][\\"abc\\"];
}

set abc(V) {
const esValue = this !== null && this !== undefined ? this : globalObject;

if (!exports.is(esValue)) {
throw new TypeError(\\"'set abc' called on an object that is not a valid instance of LegacyNoInterfaceObject.\\");
}

V = conversions[\\"DOMString\\"](V, {
context: \\"Failed to set the 'abc' property on 'LegacyNoInterfaceObject': The provided value\\"
});

esValue[implSymbol][\\"abc\\"] = V;
}
}
delete LegacyNoInterfaceObject.constructor;
Object.defineProperties(LegacyNoInterfaceObject.prototype, {
def: { enumerable: true },
abc: { enumerable: true },
[Symbol.toStringTag]: { value: \\"LegacyNoInterfaceObject\\", configurable: true }
});
if (globalObject[ctorRegistrySymbol] === undefined) {
globalObject[ctorRegistrySymbol] = Object.create(null);
}
globalObject[ctorRegistrySymbol][interfaceName] = LegacyNoInterfaceObject;
};

const Impl = require(\\"../implementations/LegacyNoInterfaceObject.js\\");
"
`;

exports[`generation without processors LegacyUnforgeable.webidl 1`] = `
"\\"use strict\\";

Expand Down
5 changes: 5 additions & 0 deletions test/cases/LegacyNoInterfaceObject.webidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Exposed=Window, LegacyNoInterfaceObject]
interface LegacyNoInterfaceObject {
attribute DOMString abc;
DOMString def();
};

0 comments on commit aedda9b

Please sign in to comment.