-
-
Notifications
You must be signed in to change notification settings - Fork 30
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
Implement [LegacyFactoryFunction]
#213
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
@@ -421,6 +421,17 @@ It is often useful for implementation classes to inherit from each other, if the | |||
|
|||
However, it is not required! The wrapper classes will have a correct inheritance chain, regardless of the implementation class inheritance chain. Just make sure that, either via inheritance or manual implementation, you implement all of the expected operations and attributes. | |||
|
|||
### 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.
@@ -421,6 +421,17 @@ It is often useful for implementation classes to inherit from each other, if the | |||
|
|||
However, it is not required! The wrapper classes will have a correct inheritance chain, regardless of the implementation class inheritance chain. Just make sure that, either via inheritance or manual implementation, you implement all of the expected operations and attributes. | |||
|
|||
### 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 aTypeError
if the interface is a legacy platform object, becausewrapper
is defined asconst wrapper
, but theProxy
creation code uses:Depends on:
new(globalObject)
for legacy platform objects #214 (merged)