From 1ec22bf3162cc274fe0cf4a5aae7ab3bd5356f65 Mon Sep 17 00:00:00 2001 From: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> Date: Wed, 22 Apr 2020 18:20:00 +0200 Subject: [PATCH] Implement [LegacyLenientSetter] and fix [LegacyLenientThis] For [LegacyLenientThis], this fixes an issue where it would still try to get the impl value, even when the thisArg did not pass the is() check, resulting in a TypeError. This also adds test coverage for [LegacyLenientThis] and [Replaceable], as part of #207. --- README.md | 2 +- lib/constructs/attribute.js | 70 +- test/__snapshots__/test.js.snap | 778 ++++++++++++++++++++-- test/cases/LegacyLenientAttributes.webidl | 9 + test/cases/Replaceable.webidl | 4 + 5 files changed, 792 insertions(+), 71 deletions(-) create mode 100644 test/cases/LegacyLenientAttributes.webidl create mode 100644 test/cases/Replaceable.webidl diff --git a/README.md b/README.md index 204b1eae..3e8989ef 100644 --- a/README.md +++ b/README.md @@ -470,6 +470,7 @@ webidl2js is implementing an ever-growing subset of the Web IDL specification. S - `[EnforceRange]` - `[Exposed]` - `[LegacyLenientThis]` +- `[LegacyLenientSetter]` - `[LegacyNoInterfaceObject]` - `[LegacyNullToEmptyString]` - `[LegacyOverrideBuiltins]` @@ -494,7 +495,6 @@ Notable missing features include: - `[Default]` (for `toJSON()` operations) - `[Global]`'s various consequences, including the named properties object and `[[SetPrototypeOf]]` - `[LegacyFactoryFunction]` -- `[LegacyLenientSetter]` - `[LegacyNamespace]` - `[LegacyTreatNonObjectAsNull]` - `[SecureContext]` diff --git a/lib/constructs/attribute.js b/lib/constructs/attribute.js index 3a9395f1..b42da313 100644 --- a/lib/constructs/attribute.js +++ b/lib/constructs/attribute.js @@ -48,8 +48,16 @@ class Attribute { setterBody = processedOutput.set; } - if (utils.getExtAttr(this.idl.extAttrs, "LegacyLenientThis")) { - brandCheck = ""; + const replaceable = utils.getExtAttr(this.idl.extAttrs, "Replaceable"); + const legacyLenientSetter = utils.getExtAttr(this.idl.extAttrs, "LegacyLenientSetter"); + const legacyLenientThis = utils.getExtAttr(this.idl.extAttrs, "LegacyLenientThis"); + + if (legacyLenientThis) { + brandCheck = ` + if (!exports.is(esValue)) { + return; + } + `; } if (sameObject) { @@ -94,23 +102,47 @@ class Attribute { ${idlConversion} ${setterBody} `, "set", { configurable }); - } else if (utils.getExtAttr(this.idl.extAttrs, "PutForwards")) { - addMethod(this.idl.name, ["V"], ` - const esValue = this !== null && this !== undefined ? this : globalObject; - ${brandCheck} - this.${this.idl.name}.${utils.getExtAttr(this.idl.extAttrs, "PutForwards").rhs.value} = V; - `, "set", { configurable }); - } else if (utils.getExtAttr(this.idl.extAttrs, "Replaceable")) { - addMethod(this.idl.name, ["V"], ` - const esValue = this !== null && this !== undefined ? this : globalObject; - ${brandCheck} - Object.defineProperty(esValue, "${this.idl.name}", { - configurable: true, - enumerable: true, - value: V, - writable: true - }); - `, "set", { configurable }); + } else { + const putForwards = utils.getExtAttr(this.idl.extAttrs, "PutForwards"); + + setterBody = ""; + if (replaceable) { + if (legacyLenientThis) { + brandCheck = ""; + } + + setterBody = ` + Object.defineProperty(esValue, "${this.idl.name}", { + configurable: true, + enumerable: true, + value: V, + writable: true + }); + `; + } else if (putForwards) { + setterBody = ` + const Q = esValue["${this.idl.name}"]; + if (!utils.isObject(Q)) { + throw new TypeError("Property '${this.idl.name}' is not an object"); + } + `; + + // WebIDL calls the `Set` abstract operation with a `Throw` value of `false`: + setterBody += `Reflect.set(Q, "${putForwards.rhs.value}", V);`; + } + + if (setterBody) { + addMethod(this.idl.name, ["V"], ` + const esValue = this !== null && this !== undefined ? this : globalObject; + ${brandCheck} + ${setterBody} + `, "set", { configurable }); + } else if (legacyLenientSetter) { + addMethod(this.idl.name, ["V"], legacyLenientThis ? "" : ` + const esValue = this !== null && this !== undefined ? this : globalObject; + ${brandCheck} + `, "set", { configurable }); + } } if (!this.static && this.idl.special === "stringifier") { diff --git a/test/__snapshots__/test.js.snap b/test/__snapshots__/test.js.snap index ec1a2b51..7f3f3c24 100644 --- a/test/__snapshots__/test.js.snap +++ b/test/__snapshots__/test.js.snap @@ -2104,6 +2104,207 @@ const Impl = require(\\"../implementations/HTMLConstructor.js\\"); " `; +exports[`with processors LegacyLenientAttributes.webidl 1`] = ` +"\\"use strict\\"; + +const conversions = require(\\"webidl-conversions\\"); +const utils = require(\\"./utils.js\\"); + +const implSymbol = utils.implSymbol; +const ctorRegistrySymbol = utils.ctorRegistrySymbol; + +const interfaceName = \\"LegacyLenientAttributes\\"; + +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 'LegacyLenientAttributes'.\`); +}; + +function makeWrapper(globalObject) { + if (globalObject[ctorRegistrySymbol] === undefined) { + throw new Error(\\"Internal error: invalid global object\\"); + } + + const ctor = globalObject[ctorRegistrySymbol][\\"LegacyLenientAttributes\\"]; + if (ctor === undefined) { + throw new Error(\\"Internal error: constructor LegacyLenientAttributes 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 LegacyLenientAttributes { + constructor() { + throw new TypeError(\\"Illegal constructor\\"); + } + + get lenientSetter() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + return esValue[implSymbol][\\"lenientSetter\\"]; + } + + set lenientSetter(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + } + + get lenientThisSetter() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"lenientThisSetter\\"]; + } + + set lenientThisSetter(V) {} + + get lenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"lenientThis\\"]; + } + + set lenientThis(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + V = conversions[\\"DOMString\\"](V, { + context: \\"Failed to set the 'lenientThis' property on 'LegacyLenientAttributes': The provided value\\" + }); + + esValue[implSymbol][\\"lenientThis\\"] = V; + } + + get readonlyLenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"readonlyLenientThis\\"]; + } + + get replaceableLenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"replaceableLenientThis\\"]; + } + + set replaceableLenientThis(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + Object.defineProperty(esValue, \\"replaceableLenientThis\\", { + configurable: true, + enumerable: true, + value: V, + writable: true + }); + } + } + Object.defineProperties(LegacyLenientAttributes.prototype, { + lenientSetter: { enumerable: true }, + lenientThisSetter: { enumerable: true }, + lenientThis: { enumerable: true }, + readonlyLenientThis: { enumerable: true }, + replaceableLenientThis: { enumerable: true }, + [Symbol.toStringTag]: { value: \\"LegacyLenientAttributes\\", configurable: true } + }); + if (globalObject[ctorRegistrySymbol] === undefined) { + globalObject[ctorRegistrySymbol] = Object.create(null); + } + globalObject[ctorRegistrySymbol][interfaceName] = LegacyLenientAttributes; + + Object.defineProperty(globalObject, interfaceName, { + configurable: true, + writable: true, + value: LegacyLenientAttributes + }); +}; + +const Impl = require(\\"../implementations/LegacyLenientAttributes.js\\"); +" +`; + exports[`with processors LegacyUnforgeable.webidl 1`] = ` "\\"use strict\\"; @@ -3777,6 +3978,143 @@ const Impl = require(\\"../implementations/Reflect.js\\"); " `; +exports[`with processors Replaceable.webidl 1`] = ` +"\\"use strict\\"; + +const conversions = require(\\"webidl-conversions\\"); +const utils = require(\\"./utils.js\\"); + +const implSymbol = utils.implSymbol; +const ctorRegistrySymbol = utils.ctorRegistrySymbol; + +const interfaceName = \\"Replaceable\\"; + +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 'Replaceable'.\`); +}; + +function makeWrapper(globalObject) { + if (globalObject[ctorRegistrySymbol] === undefined) { + throw new Error(\\"Internal error: invalid global object\\"); + } + + const ctor = globalObject[ctorRegistrySymbol][\\"Replaceable\\"]; + if (ctor === undefined) { + throw new Error(\\"Internal error: constructor Replaceable 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 Replaceable { + constructor() { + throw new TypeError(\\"Illegal constructor\\"); + } + + get replaceable() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + return esValue[implSymbol][\\"replaceable\\"]; + } + + set replaceable(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + Object.defineProperty(esValue, \\"replaceable\\", { + configurable: true, + enumerable: true, + value: V, + writable: true + }); + } + } + Object.defineProperties(Replaceable.prototype, { + replaceable: { enumerable: true }, + [Symbol.toStringTag]: { value: \\"Replaceable\\", configurable: true } + }); + if (globalObject[ctorRegistrySymbol] === undefined) { + globalObject[ctorRegistrySymbol] = Object.create(null); + } + globalObject[ctorRegistrySymbol][interfaceName] = Replaceable; + + Object.defineProperty(globalObject, interfaceName, { + configurable: true, + writable: true, + value: Replaceable + }); +}; + +const Impl = require(\\"../implementations/Replaceable.js\\"); +" +`; + exports[`with processors RequestDestination.webidl 1`] = ` "\\"use strict\\"; @@ -10251,27 +10589,153 @@ exports._internalSetup = (wrapper, globalObject) => { throw new TypeError(\\"Illegal invocation\\"); } - V = conversions[\\"unsigned long\\"](V, { - context: \\"Failed to set the 'length' property on 'Global': The provided value\\" - }); + V = conversions[\\"unsigned long\\"](V, { + context: \\"Failed to set the 'length' property on 'Global': The provided value\\" + }); + + esValue[implSymbol][\\"length\\"] = V; + }, + [Symbol.iterator]: Array.prototype[Symbol.iterator], + keys: Array.prototype.keys, + values: Array.prototype[Symbol.iterator], + entries: Array.prototype.entries, + forEach: Array.prototype.forEach + }) + ); + + Object.defineProperties(wrapper, { + unforgeableOp: { configurable: false, writable: false }, + unforgeableAttr: { configurable: false }, + [Symbol.iterator]: { enumerable: false } + }); +}; + +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([\\"Global\\"]); + +exports.install = (globalObject, globalNames) => { + if (!globalNames.some(globalName => exposed.has(globalName))) { + return; + } + class Global { + constructor() { + throw new TypeError(\\"Illegal constructor\\"); + } + + static staticOp() { + return Impl.implementation.staticOp(); + } + + static get staticAttr() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + return Impl.implementation[\\"staticAttr\\"]; + } + + static set staticAttr(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + return Impl.implementation[\\"staticAttr\\"]; + } + } + Object.defineProperties(Global.prototype, { [Symbol.toStringTag]: { value: \\"Global\\", configurable: true } }); + Object.defineProperties(Global, { staticOp: { enumerable: true }, staticAttr: { enumerable: true } }); + if (globalObject[ctorRegistrySymbol] === undefined) { + globalObject[ctorRegistrySymbol] = Object.create(null); + } + globalObject[ctorRegistrySymbol][interfaceName] = Global; + + Object.defineProperty(globalObject, interfaceName, { + configurable: true, + writable: true, + value: Global + }); +}; + +const Impl = require(\\"../implementations/Global.js\\"); +" +`; + +exports[`without processors HTMLConstructor.webidl 1`] = ` +"\\"use strict\\"; + +const conversions = require(\\"webidl-conversions\\"); +const utils = require(\\"./utils.js\\"); + +const implSymbol = utils.implSymbol; +const ctorRegistrySymbol = utils.ctorRegistrySymbol; + +const interfaceName = \\"HTMLConstructor\\"; + +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 'HTMLConstructor'.\`); +}; + +function makeWrapper(globalObject) { + if (globalObject[ctorRegistrySymbol] === undefined) { + throw new Error(\\"Internal error: invalid global object\\"); + } + + const ctor = globalObject[ctorRegistrySymbol][\\"HTMLConstructor\\"]; + if (ctor === undefined) { + throw new Error(\\"Internal error: constructor HTMLConstructor is not installed on the passed global object\\"); + } + + return Object.create(ctor.prototype); +} - esValue[implSymbol][\\"length\\"] = V; - }, - [Symbol.iterator]: Array.prototype[Symbol.iterator], - keys: Array.prototype.keys, - values: Array.prototype[Symbol.iterator], - entries: Array.prototype.entries, - forEach: Array.prototype.forEach - }) - ); +exports.create = (globalObject, constructorArgs, privateData) => { + const wrapper = makeWrapper(globalObject); + return exports.setup(wrapper, globalObject, constructorArgs, privateData); +}; - Object.defineProperties(wrapper, { - unforgeableOp: { configurable: false, writable: false }, - unforgeableAttr: { configurable: false }, - [Symbol.iterator]: { enumerable: false } - }); +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; @@ -10304,52 +10768,37 @@ exports.new = globalObject => { return wrapper[implSymbol]; }; -const exposed = new Set([\\"Global\\"]); +const exposed = new Set([\\"Window\\"]); exports.install = (globalObject, globalNames) => { if (!globalNames.some(globalName => exposed.has(globalName))) { return; } - class Global { + class HTMLConstructor { constructor() { throw new TypeError(\\"Illegal constructor\\"); } - - static staticOp() { - return Impl.implementation.staticOp(); - } - - static get staticAttr() { - const esValue = this !== null && this !== undefined ? this : globalObject; - - return Impl.implementation[\\"staticAttr\\"]; - } - - static set staticAttr(V) { - const esValue = this !== null && this !== undefined ? this : globalObject; - - return Impl.implementation[\\"staticAttr\\"]; - } } - Object.defineProperties(Global.prototype, { [Symbol.toStringTag]: { value: \\"Global\\", configurable: true } }); - Object.defineProperties(Global, { staticOp: { enumerable: true }, staticAttr: { enumerable: true } }); + Object.defineProperties(HTMLConstructor.prototype, { + [Symbol.toStringTag]: { value: \\"HTMLConstructor\\", configurable: true } + }); if (globalObject[ctorRegistrySymbol] === undefined) { globalObject[ctorRegistrySymbol] = Object.create(null); } - globalObject[ctorRegistrySymbol][interfaceName] = Global; + globalObject[ctorRegistrySymbol][interfaceName] = HTMLConstructor; Object.defineProperty(globalObject, interfaceName, { configurable: true, writable: true, - value: Global + value: HTMLConstructor }); }; -const Impl = require(\\"../implementations/Global.js\\"); +const Impl = require(\\"../implementations/HTMLConstructor.js\\"); " `; -exports[`without processors HTMLConstructor.webidl 1`] = ` +exports[`without processors LegacyLenientAttributes.webidl 1`] = ` "\\"use strict\\"; const conversions = require(\\"webidl-conversions\\"); @@ -10358,7 +10807,7 @@ const utils = require(\\"./utils.js\\"); const implSymbol = utils.implSymbol; const ctorRegistrySymbol = utils.ctorRegistrySymbol; -const interfaceName = \\"HTMLConstructor\\"; +const interfaceName = \\"LegacyLenientAttributes\\"; exports.is = value => { return utils.isObject(value) && utils.hasOwn(value, implSymbol) && value[implSymbol] instanceof Impl.implementation; @@ -10370,7 +10819,7 @@ exports.convert = (value, { context = \\"The provided value\\" } = {}) => { if (exports.is(value)) { return utils.implForWrapper(value); } - throw new TypeError(\`\${context} is not of type 'HTMLConstructor'.\`); + throw new TypeError(\`\${context} is not of type 'LegacyLenientAttributes'.\`); }; function makeWrapper(globalObject) { @@ -10378,9 +10827,9 @@ function makeWrapper(globalObject) { throw new Error(\\"Internal error: invalid global object\\"); } - const ctor = globalObject[ctorRegistrySymbol][\\"HTMLConstructor\\"]; + const ctor = globalObject[ctorRegistrySymbol][\\"LegacyLenientAttributes\\"]; if (ctor === undefined) { - throw new Error(\\"Internal error: constructor HTMLConstructor is not installed on the passed global object\\"); + throw new Error(\\"Internal error: constructor LegacyLenientAttributes is not installed on the passed global object\\"); } return Object.create(ctor.prototype); @@ -10436,27 +10885,117 @@ exports.install = (globalObject, globalNames) => { if (!globalNames.some(globalName => exposed.has(globalName))) { return; } - class HTMLConstructor { + class LegacyLenientAttributes { constructor() { throw new TypeError(\\"Illegal constructor\\"); } + + get lenientSetter() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + return esValue[implSymbol][\\"lenientSetter\\"]; + } + + set lenientSetter(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + } + + get lenientThisSetter() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"lenientThisSetter\\"]; + } + + set lenientThisSetter(V) {} + + get lenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"lenientThis\\"]; + } + + set lenientThis(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + V = conversions[\\"DOMString\\"](V, { + context: \\"Failed to set the 'lenientThis' property on 'LegacyLenientAttributes': The provided value\\" + }); + + esValue[implSymbol][\\"lenientThis\\"] = V; + } + + get readonlyLenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"readonlyLenientThis\\"]; + } + + get replaceableLenientThis() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + return; + } + + return esValue[implSymbol][\\"replaceableLenientThis\\"]; + } + + set replaceableLenientThis(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + Object.defineProperty(esValue, \\"replaceableLenientThis\\", { + configurable: true, + enumerable: true, + value: V, + writable: true + }); + } } - Object.defineProperties(HTMLConstructor.prototype, { - [Symbol.toStringTag]: { value: \\"HTMLConstructor\\", configurable: true } + Object.defineProperties(LegacyLenientAttributes.prototype, { + lenientSetter: { enumerable: true }, + lenientThisSetter: { enumerable: true }, + lenientThis: { enumerable: true }, + readonlyLenientThis: { enumerable: true }, + replaceableLenientThis: { enumerable: true }, + [Symbol.toStringTag]: { value: \\"LegacyLenientAttributes\\", configurable: true } }); if (globalObject[ctorRegistrySymbol] === undefined) { globalObject[ctorRegistrySymbol] = Object.create(null); } - globalObject[ctorRegistrySymbol][interfaceName] = HTMLConstructor; + globalObject[ctorRegistrySymbol][interfaceName] = LegacyLenientAttributes; Object.defineProperty(globalObject, interfaceName, { configurable: true, writable: true, - value: HTMLConstructor + value: LegacyLenientAttributes }); }; -const Impl = require(\\"../implementations/HTMLConstructor.js\\"); +const Impl = require(\\"../implementations/LegacyLenientAttributes.js\\"); " `; @@ -12118,6 +12657,143 @@ const Impl = require(\\"../implementations/Reflect.js\\"); " `; +exports[`without processors Replaceable.webidl 1`] = ` +"\\"use strict\\"; + +const conversions = require(\\"webidl-conversions\\"); +const utils = require(\\"./utils.js\\"); + +const implSymbol = utils.implSymbol; +const ctorRegistrySymbol = utils.ctorRegistrySymbol; + +const interfaceName = \\"Replaceable\\"; + +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 'Replaceable'.\`); +}; + +function makeWrapper(globalObject) { + if (globalObject[ctorRegistrySymbol] === undefined) { + throw new Error(\\"Internal error: invalid global object\\"); + } + + const ctor = globalObject[ctorRegistrySymbol][\\"Replaceable\\"]; + if (ctor === undefined) { + throw new Error(\\"Internal error: constructor Replaceable 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 Replaceable { + constructor() { + throw new TypeError(\\"Illegal constructor\\"); + } + + get replaceable() { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + return esValue[implSymbol][\\"replaceable\\"]; + } + + set replaceable(V) { + const esValue = this !== null && this !== undefined ? this : globalObject; + + if (!exports.is(esValue)) { + throw new TypeError(\\"Illegal invocation\\"); + } + + Object.defineProperty(esValue, \\"replaceable\\", { + configurable: true, + enumerable: true, + value: V, + writable: true + }); + } + } + Object.defineProperties(Replaceable.prototype, { + replaceable: { enumerable: true }, + [Symbol.toStringTag]: { value: \\"Replaceable\\", configurable: true } + }); + if (globalObject[ctorRegistrySymbol] === undefined) { + globalObject[ctorRegistrySymbol] = Object.create(null); + } + globalObject[ctorRegistrySymbol][interfaceName] = Replaceable; + + Object.defineProperty(globalObject, interfaceName, { + configurable: true, + writable: true, + value: Replaceable + }); +}; + +const Impl = require(\\"../implementations/Replaceable.js\\"); +" +`; + exports[`without processors RequestDestination.webidl 1`] = ` "\\"use strict\\"; diff --git a/test/cases/LegacyLenientAttributes.webidl b/test/cases/LegacyLenientAttributes.webidl new file mode 100644 index 00000000..2a212041 --- /dev/null +++ b/test/cases/LegacyLenientAttributes.webidl @@ -0,0 +1,9 @@ +[Exposed=Window] +interface LegacyLenientAttributes { + [LegacyLenientSetter] readonly attribute DOMString lenientSetter; + [LegacyLenientSetter, LegacyLenientThis] readonly attribute DOMString lenientThisSetter; + + [LegacyLenientThis] attribute DOMString lenientThis; + [LegacyLenientThis] readonly attribute DOMString readonlyLenientThis; + [LegacyLenientThis, Replaceable] readonly attribute DOMString replaceableLenientThis; +}; diff --git a/test/cases/Replaceable.webidl b/test/cases/Replaceable.webidl new file mode 100644 index 00000000..2733d464 --- /dev/null +++ b/test/cases/Replaceable.webidl @@ -0,0 +1,4 @@ +[Exposed=Window] +interface Replaceable { + [Replaceable] readonly attribute DOMString replaceable; +};