This document describes the process for converting old style Extensions IDL schema files to modern WebIDL syntax and details rules for how to handle specific conversion cases.
For a long time Extension API schema files have used an old unmaintained IDL parser, which has fallen out of date with modern WebIDL. Recently support for a modern Blink maintained WebIDL parser was added (crbug.com/340297705), which means we are now able to start updating our IDL schema files to modern WebIDL.
When converting an IDL file a new file should be created in the same location as the old schema with the same name but using a .webidl
suffix instead. Once the converted file has been created, it must be verified to have no differences from the output of the original by running the tools/json_schema_compiler/web_idl_diff_tool.py
utility, which takes the filename of the old and the new schema as arguments. e.g. tools/json_schema_compiler/web_idl_diff_tool.py extensions/common/api/alarms.idl extensions/common/api/alarms.webidl
Only after it is verified that there is no differences by the tool outputting No difference found!
, the old .idl
schema file can be moved to tools/json_schema_compiler/test/converted_schemas/
along with a copy of the newly converted .webidl
schema. Then tools/json_schema_compiler/web_idl_diff_tool_test.py
should be updated to add these filenames to the converted_schemas
array and web_idl_diff_tool_test.py
should be run to verify it passes with the newly added entry. Finally, the associated schema.gni
file with the old .idl
filename will need to be updated to .webidl
.
The following conversion rules and the provided alarms
API conversion example can be used as a guide for structure, syntax, and style.
The top-level namespace
declaration is removed.
namespace foo { ... }
becomes the new top-level interface Foo { ... }
. Note the capitalization change from foo
to Foo
.partial interface Browser
is added at the end of the file to expose the API on the browser
object. For an API named foo
, this should be:interface Foo { ... } partial interface Browser { static attribute Foo foo; };
system.cpu
would become:// Note the interface name here is only the final part of the API name. interface CPU { ... } partial interface System { static attribute CPU cpu; } partial interface Browser { static attribute System system; }
Dictionaries are moved outside the main interface to the top level of the file. Their internal structure remains the same. Descriptive comments above them should be moved along with them. For dictionary members, non-optional members must be prefixed with required
, and optional members should not have a ?
suffix. e.g.
dictionary MyDictionary { required DOMString requiredMember; DOMString optionalMember; };
Enums are moved outside the main interface to the top level of the file. Their internal structure remains very similar, but the values are instead defined with quoted strings e.g.
enum VendorIdSource { "bluetooth", "usb" };
Each enum value should be put on a new line. Descriptive comments above the whole enum should be moved along with them.
All functions that used a trailing callback must be converted to return a Promise
.
static void
to static Promise<T>
.Promise<T>
is determined by the arguments of the old callback:void(Type arg)
becomes Promise<Type>
. For example:void(Alarm alarm)
becomes Promise<Alarm>
.void(optional DOMString foo
becomes Promise<DOMString?>
.void()
becomes Promise<undefined>
.void(optional Type arg)
becomes a nullable promise type Promise<Type?>
.void(Type[] arg)
becomes a sequence Promise<sequence<Type>>
.[requiredCallback]
Attribute: If the original callback was not optional, you must add the [requiredCallback]
extended attribute before the static Promise
return type.void
keyword should be replaced with undefined
.The documentation comments for functions need to be updated.
|callback|
parameter should be changed to |Returns|
, otherwise there is no need for a |Returns|
description.|PromiseValue|
comment should be added to document what the promise resolves to, using the name from the old callback parameter. For example, if the old callback was void(boolean wasCleared)
, the new comment would be |PromiseValue|: wasCleared
.|PromiseValue|: name
comment separated with a colon+space. For example, if the old callback was:// Description of the callback. // |param| : A param description. callback FunctionCallback = void(SomeType param); ... // Description of the function. // |callback| : Called when the function is done. static void someFunction(FunctionCallback callback);
This would become:
// Description of the function. // |Returns|: Called when the function is done. // |PromiseValue|: param: A param description. static Promise<SomeType> someFunction();
|Returns|
and a |PromiseValue|
if needed.The old interface Events { ... }
is replaced with a more explicit event handling interface. For each event, such as onFoo
, follow these steps:
OnFooListener
. If the argument passed to the callback had a comment description previously, that should be moved to the new callback definition; otherwise, it does not need a comment describing that argument.// Fired when an alarm has elapsed. Useful for event pages. // |alarm|: The alarm that has elapsed. static void onAlarm(Alarm alarm);
Would become:
// Listener callback for the onAlarm event. // |alarm|: The alarm that has elapsed. callback OnAlarmListener = undefined (Alarm alarm);
OnFooEvent
that inherits from ExtensionEvent
and includes the standard addListener
, removeListener
, and hasListener
methods. This interface should come directly after the corresponding callback definition.interface OnAlarmEvent : ExtensionEvent { static undefined addListener(OnAlarmListener listener); static undefined removeListener(OnAlarmListener listener); static boolean hasListener(OnAlarmListener listener); };
Alarms
), add a static attribute
for the event. If the original event definition had a general comment describing it, that should be moved above this new attribute.// Fired when an alarm has elapsed. Useful for event pages. static attribute OnAlarmEvent onAlarm;
The ./test/converted_schemas/
folder contains examples of previous conversions that can be used as reference for other syntax and formatting. An example of the alarms conversion from that folder:
Old alarms IDL: @./test/converted_schemas/alarms.idl
New alarms WebIDL: @./test/converted_schemas/alarms.webidl