Tools to generate Dart interfaces from TypeScript declaration files and Web IDL definitions.
This package is used to generate
web from Web IDL definitions
and MDN API documentation.
The tools to generate bindings are written in Dart, compiled to JavaScript, and run on Node.
There are two entrypoints present in this package:
gen_interop_bindings.dart: This entrypoint is for generating Dart interfaces from TS Declaration code, given the path to a.d.tsfileupdate_idl_bindings.dart: This entrypoint is for generating Dart interfaces from Web IDL definitions, given the path to a.idlfile. If no idl file is present, it, by default, generates code forpackage:web.
The web_generator requires Node.js v22 or newer. Older Node versions are not supported and may result in runtime failures.
To generate Dart interfaces for a given .d.ts file, run the following at the root of this package:
dart bin/gen_interop_bindings.dart <input.d.ts>
dart bin/gen_interop_bindings.dart -o <output> <input>If multiple files are passed, the output option is regarded as an output directory instead.
For more information on the command-line options you can pass alongside, you can check the help information
dart bin/gen_interop_bindings.dart --helpThe generator also has support for configurating the output of the generator, allowing support for configuring features like: variardic argument count, preamble (if any), TS Compiler Options, etc.
These configuration options can either be passed from the command line, or via a YAML configuration file. To pass a configuration file, pass the --config option.
Given a sample configuration file:
input: a.d.ts
output: b.d.ts
ts-config-file: tsconfig.jsonThe following are equivalent
dart bin/gen_interop_bindings.dart -o b.d.ts --ts-config tsconfig.json a.d.ts
dart bin/gen_interop_bindings.dart --config config.yamlNote that not all configuration options are direct mappings between the CLI and the configuration file.
| Option | Description | Example |
|---|---|---|
name |
The name of the bindings | |
description |
A description of the bindings (optional) | |
preamble |
Preamble text to insert before the bindings (optional) |
|
input |
A file (single string) or set of files (array of strings) passed into the generator | or
|
output |
The output file or directory to write the bindings to | |
include |
Declarations to include in the generated output (as a list). Can either be passed as a raw string to match the full name, or as a regular expression. By default, the generator outputs all exported declarations |
|
language_version |
The Dart Language Version to use, usually for formatting (optional) | |
ts_config |
An object consisting of TS Configurations following the tsconfig.json file schema used for configuring the TypeScript Program/Compiler (optional) |
|
ts_config_file |
The TS Configuration file (tsconfig.json) if any (optional) | |
generate_all |
Include generating declarations for code that isn't exported. Defaults to false | |
ignore_errors |
Ignore source code warnings and errors (they will still be printed). Defaults to false | |
functions.varargs |
The number of arguments that variable-argument functions should take. Defaults to 4 |
|
The generator scripts use a number of conventions to consistently handle TS definitions:
- Top level declarations are handled as top level dart
externaldeclarations annotated with@JS.
- Enums are represented as extension types with static members.
- In most cases, values are known beforehand, so the representation types of the resulting extension types are Dart primitive types with non-external static members.
- If the value for an enum is not given, then the representation type is an interop type, and any members without a value are marked as
external
- Interfaces and Classes are emitted as extension types that wrap and implement
JSObject - Interface and Class inheritance is maintained using
implementsbetween extension types - Classes have default constructors if none are provided
- Interface and Classes support members such as: properties, functions, operators,
calldeclarations, construct signatures, getters and setters. - Readonly properties are represented as getters.
- Overriding signatures are annotated with
@redeclare. - Multiple instances of interfaces in a given scope are merged together into a single interface. Also supports merging with
vardeclarations.
- Namespaces in TS are converted to extension types on
JSObjectwith static members. - Typed declarations (such as enums, classes, interfaces and namespaces) are prefixed and generated in the general module space.
- Constructor calls for classes are generated for every class in a namespace as a static redirect method.
- Namespaces nested inside the namespace are as well generated as static getters on the namespace, which are references to the namespaces themselves.
- Supports overloading and declaration merging with classes, interfaces, enums,
vardeclarations, and functions.
- Supports mapping basic JS types to Dart
js_interoptypes. nevertype returned from a const declaration, function, readonly property or method has the declaration annotated with@doNotStore.- Supports automatically mapping web types to
package:webtypes - Anonymous Unions/Intersections: Anonymous unions and intersections are represented as extension types with cast members to cast the value as a type in the union/intersection. If the union is homogenous and contains strings/numbers, then it is generated more like an enum, with specific static values. An intersection with
nullorundefinedequalsnever - Anonymous Objects: Anonymous objects are represented similar to interface declarations, with an object literal constructor.
- Anonymous Closures and Construct Signatures: Anonymous closures and construct signatures are represented as extension types on
JSFunctionoverriding thecallmethod. This allows for a stronger type signature than justJSFunction. While closures leave their calls asexternal, construct signatures just redirect to the class constructor. - Generic types are represented as normal Dart generics, and they are constrained by
JSAnyby default. typeofdeclarations are references to the type of the declaration, which are:- Variable: The variable's type
- Enum: An object representation of the enum (in order to support
keyofcorrectly). - Function:
JSFunction - Otherwise, the extension type representation of the type that it refers to is used.
keyofdeclarations are represented as unions of the keys for the operand type.
- Supports importing/exporting declarations. If the files that are being imported are included in input, then such references are treated as imports in Dart, else the declarations are generated in-place.
- Supports documentation (JSDoc), and maps some annotations to Dart annotations such as
@deprecatedand@experimental
To generate Dart interfaces for a given .idl file, run the following at the root of this package:
dart bin/update_idl_bindings.dartIf multiple files are passed, the output option is regarded as an output directory instead.
To regenerate web bindings from the current IDL versions, run the entrypoint without any arguments:
dart bin/update_idl_bindings.dartTo re-generate the package from newer IDL versions, you can either run:
dart bin/update_idl_bindings.dart --updateor, manually edit lib/src/package.json to use specific IDL versions, and
re-run update_idl_bindings.dart.
package:web's dartdoc comments come from the MDN Web Docs project. In order to update to the latest version of the documentation, run:
dart bin/scrape_mdn.dartThat will collect the MDN documentation into third_party/mdn/mdn.json; changes
to that file should be committed to git. You'll need to run
update_idl_bindings.dart to produce Dart code using the updated documentation.
The generator scripts use a number of conventions to consistently handle Web IDL definitions:
- Interfaces are emitted as extension types that wrap and implement
JSObject. - Interface inheritance is maintained using
implementsbetween extension types. - Members of partial interfaces, partial mixins, and mixins are added to the interfaces that include them, and therefore do not have separate declarations.
- Generic types include the generic in the case of
JSArrayandJSPromise. - Enums are typedef'd to
String. - Callbacks and callback interfaces are typedef'd to
JSFunction. - In general, we prefer the Dart primitive over the JS type equivalent wherever
possible. For example, APIs use
Stringinstead ofJSString. - If a type appears in a generic position and it was typedef'd to a Dart
primitive type, it is replaced with the JS type equivalent to respect the type
bound of
JSAny?. - Union types are computed by picking the least upper bound of the types in the
JS type hierarchy, where every interface is equivalent to
JSObject. - Dictionary and typedef types are only emitted if they're used by another API.
- The generator uses the MDN compatibility data to determine what members, interfaces, and namespaces to emit. Currently, we only emit code that is standards track and is not experimental to reduce the number of breaking changes.
To ignore the compatibility data and emit all members, run:
dart bin/update_idl_bindings.dart --generate-allThis is useful if you want to avoid having to write bindings manually for some experimental and non-standard APIs.
Based on:
| Item | Version |
|---|---|
@webref/css |
6.20.3 |
@webref/elements |
2.4.0 |
@webref/idl |
3.60.1 |