-
-
Couldn't load subscription status.
- Fork 31
Implement [LegacyFactoryFunction]
#213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Implement [LegacyFactoryFunction]
#213
Conversation
Let's remove that complexity. We can add a constraint to the Web IDL spec that prohibits more than one LegacyFactoryFunction instead. |
f8a21b8 to
0176da0
Compare
a6a36fb to
f8cb248
Compare
|
The generated snapshots here seem overcomplicated, and it's not clear why you're modifying existing functionality (like I think the root of the problem is that you're trying to construct the const thisArgument = exports.new(globalObject, new.target);
const result = Impl.legacyFactoryFunction.call(thisArgument, globalObject, ...args);
return utils.tryWrapperForImpl(utils.isObject(result) ? result : thisArgument);to instead be return utils.wrapperForImpl(Impl.legacyFactoryFunction(globalObject, ...args)); |
|
@domenic That won’t support the case when |
|
Hmm. I see there are references to NewTarget in https://heycam.github.io/webidl/#legacy-factory-functions but I am unsure whether they are implemented, or if they are, whether they're necessary for web compatibility. |
|
@domenic All browsers implement the NewTarget handling (web-platform-tests/wpt#27991), so it’s probably necessary for web compatibility. |
f8cb248 to
877562d
Compare
|
@ExE-Boss want to rebase this and finish review and then we can do a new release? |
877562d to
78b8796
Compare
[LegacyFactoryFunction]
069ac03 to
94841f4
Compare
94841f4 to
4a7471e
Compare
|
|
||
| ### The `[LegacyFactoryFunction]` extended attribute | ||
|
|
||
| For interfaces which have the `[LegacyFactoryFunction]` extended attribute, the implementation class file must contain the `legacyFactoryFunction` export, with the signature `(thisValue, globalObject, [...legacyFactoryFunctionArgs], { newTarget, wrapper })`, which is used for: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to pass the thisValue as the first parameter, rather than this so that it’s possible to use arrow functions for this:
exports.legacyFactoryFunction = (thisValue, globalObject, [...args], { newTarget, wrapper }) => {
// code
}I also decided to include the new.target and wrapper in a privateData object to match constructor(globalObject, args, privateData).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would jsdom's implementations of the relevant parts of the HTML spec actually use any of thisValue, newTarget, or wrapper? If not, let's exclude them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should at the very least include thisValue and pass the args as an array to leave open the possibility of a privateData bag in case https://html.spec.whatwg.org/multipage/media.html#dom-audio, https://html.spec.whatwg.org/multipage/embedded-content.html#dom-image and https://html.spec.whatwg.org/multipage/form-elements.html#dom-option are rewritten.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still feeling like this is over-complex given that there are literally three cases and we know exactly how they behave. Our goal here is not to have a general framework to do any possible LegacyFactoryFunction; it's to implement Option, Audio, and Image.
In particular, I'd like to see these either support return override, or use the passed in thisValue, but not both. I suspect thisValue would be simpler, and perhaps necessary to support class X extends Audio {}. So I suspect the correct signature here will be (thisValue, globalObject, [...args]) with no support for return-override.
| @@ -0,0 +1,6 @@ | |||
| // Simplified from https://html.spec.whatwg.org/multipage/form-elements.html#htmloptionelement | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What value does having these three tests give, instead of just one of them? I can see zero-args vs. nonzero, but these three cases don't seem to differ in interesting ways.
|
|
||
| ### The `[LegacyFactoryFunction]` extended attribute | ||
|
|
||
| For interfaces which have the `[LegacyFactoryFunction]` extended attribute, the implementation class file must contain the `legacyFactoryFunction` export, with the signature `(thisValue, globalObject, [...legacyFactoryFunctionArgs], { newTarget, wrapper })`, which is used for: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would jsdom's implementations of the relevant parts of the HTML spec actually use any of thisValue, newTarget, or wrapper? If not, let's exclude them.
| `; | ||
|
|
||
| // This implements the WebIDL legacy factory function behavior, as well as support for overridding | ||
| // the return type, which is used by HTML's element legacy factory functions: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems more likely to be a historical artifact of how the spec is written?
It seems like we should be able to support either return overload (like HTML uses for its LegacyFactoryFunctions), or generate a this value (like modern Web IDL-using constructor specs do). We shouldn't need both, I don't think?
In particular given that you can subclass Option per the tests you wrote, I suspect the first line of https://html.spec.whatwg.org/#dom-option is just incorrect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It occurred to me that the order of Impl.legacyFactoryFunction and Impl.init calls is wrong, so I’m fixing that so that the object returned from Impl.legacyFactoryFunction is now the impl, and the result of makeWrapper is what’s returned from the LegacyFactoryFunction constructor.
This also makes it possible to support returning the result of new Impl.implementation.
This implements
[LegacyFactoryFunction].Unlike Chromium’s implementation, which assumes that a single interface will only ever have at most one legacy factory function, this implementation makes it possible to define more than one legacy factory function per interface, as can be seen withtest/cases/LegacyFactoryFunction.webidl.While working on this, I’ve noticed that
exports.new(globalObject)will unconditionally throw aTypeErrorif the interface is a legacy platform object, becausewrapperis defined asconst wrapper, but theProxycreation code uses:Depends on:
new(globalObject)for legacy platform objects #214 (merged)