Add .webidl file(s) in this folder for each interface that you want to implement. If one already exists, you want to add the missing parts to it.
For each interface, this will generate a trait named {interface_name}Methods,
accessible via use crate::dom::bindings::codegen::Bindings::{interface_name}Binding.
Use this trait by:
Adding a matching struct, using #[dom_struct]
Adding methods with todo! bodies.
At this point, the struct can have only one member: reflector_: Reflector,
The struct should be documented with a link to its interface in the spec,
The trait methods should each be documented with a link to their definition in the interface.
Using what you know, for each internal slot of the interface:
Add an appropriate member to the struct(s) added at 4.
If this requires defining other structs or enums, these should derive JSTraceable and MallocSizeOf(example).
All JSTraceable structs added above that contain members that must be rooted because they are either JS values or Dom Objects should be marked with #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]. Example, where the lint is needed due to the presence of a JSVal.
If such a struct is assigned to a variable, impl js::gc::Rootable for the and use rooted! to root the variable(example).
All of this can be changed later, so simply use your best judgement at this stage.
Add methods for construction(not to be confused with a Constructor that is part of the Web API).
For each methods of the bindings trait referred to at 3 in Part 1:
In general, follow the structure of the spec: if a method calls into another named algorithm, implement that named algorithm as a separate private method of your struct, that the trait methods calls into. If you later realize this private method can be used from other structs, make it pub(crate).
For each algorithm step in the spec:
Copy the line from the spec.
Implement the spec in code(which may take more than one line, and might require additional commenting).
Note: there are certain things that are often needed to perform operation as part of an algorithm:
SafeJSContext: can be obtained using GlobalScope::get_cx().
GlobalScope: can be obtained using self.global() on a dom_struct, or GlobalScope::from_safe_context
InRealm: can be obtained as an argument to the generated trait method, using this configuration file
CanGc: same as for InRealm.
It is best to access them as early as possible, say at the top of the trait method implementation, and to pass them down(as ref for GlobalScope) as arguments, in the order described above(with any other needed argument coming in between &GlobalScope and InRealm).
Now comes the time to identify which WPT test to run against your first draft. You can find them here.
This may require turning them on, using this config.
Test may fail because:
There is a bug in the code. These should be fixed.
The test uses other APIs that aren't supported yet(usually ERROR).
Bugs should be fixed. Copilot is of little help here.
Expected failures can be marked as such, using the process described here.
This part is done when there are no unexpected test results left.
On occasion, on the advice of a reviewer, you may file an issue and describe a failure that you cannot fix, mark the test as a failure, and leave it to a follow-up.