blob: 0c1e3e1fc15e52e70de9f067b9eef8eef008f760 [file] [log] [blame] [view] [edit]
## What's this?
Tools to generate Dart interfaces from TypeScript declaration files and Web IDL definitions.
This package is used to generate
[`web`](https://github.com/dart-lang/web/tree/main/web) from Web IDL definitions
and MDN API documentation.
## Using this
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.ts` file
- `update_idl_bindings.dart`: This entrypoint is for generating Dart interfaces from Web IDL definitions, given the path to a `.idl` file. If no idl file is present, it, by default, generates code for `package:web`.
## TS Declarations
To generate Dart interfaces for a given `.d.ts` file, run the following at the root of this package:
```shell
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
```shell
dart bin/gen_interop_bindings.dart --help
```
### Configuration
The 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:
```yaml
input: a.d.ts
output: b.d.ts
ts-config-file: tsconfig.json
```
The following are equivalent
```shell
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.yaml
```
Note that not all configuration options are direct mappings between the CLI and the configuration file.
### Configuration File Reference
| Option | Description | Example |
|--------|-------------|---------|
| `name` | The name of the bindings | <pre>`name: MyBindings`</pre> |
| `description` | A description of the bindings (optional) | <pre>`description: My awesome bindings`</pre> |
| `preamble` | Preamble text to insert before the bindings (optional) | <pre>`preamble: \|`<br>` // Generated. Do not edit.`</pre> |
| `input` | A file (single string) or set of files (array of strings) passed into the generator | <pre>`input: bindings.d.ts`</pre> <br/> or <br/> <pre>`input: `<br>` - bindings.d.ts`</pre> |
| `output` | The output file or directory to write the bindings to | <pre>`output: lib/src/js`</pre> |
| `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** | <pre>`include: `<br>` - myNumber`</pre> |
| `language_version` | The Dart Language Version to use, usually for formatting (optional) | <pre>`language_version: 3.6.0`</pre> |
| `ts_config` | An object consisting of TS Configurations following the [tsconfig.json file schema](https://www.typescriptlang.org/tsconfig/) used for configuring the TypeScript Program/Compiler (optional) | <pre>`ts_config: `<br>` compilerOptions: `<br>` target: es2020`</pre> |
| `ts_config_file` | The TS Configuration file (tsconfig.json) if any (optional) | <pre>`ts_config_file: tsconfig.json`</pre> |
| `generate_all` | Include generating declarations for code that isn't exported. Defaults to false | <pre>`generate_all: true`</pre> |
| `ignore_errors` | Ignore source code warnings and errors (they will still be printed). Defaults to false | <pre>`ignore_errors: true`</pre> |
| `functions.varargs` | The number of arguments that variable-argument functions should take. Defaults to 4 | <pre>`functions: `<br>` varargs: 6`</pre> |
### Conventions
The generator scripts use a number of conventions to consistently handle TS
definitions:
#### Top Level Declarations
- Top level declarations are handled as top level dart `external` declarations annotated with `@JS`.
#### Enums
- 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
- Interfaces and Classes are emitted as extension types that wrap and implement `JSObject`
- Interface and Class inheritance is maintained using `implements` between extension types
- Classes have default constructors if none are provided
- Interface and Classes support members such as: properties, functions, operators, `call` declarations, construct signatures, getters and setters.
- Readonly properties are represented as getters.
- Overriding signatures are annotated with [`@redeclare`](https://pub.dev/documentation/meta/latest/meta/redeclare-constant.html).
- Multiple instances of interfaces in a given scope are merged together into a single interface. Also supports merging with `var` declarations.
#### Namespaces
- Namespaces in TS are converted to extension types on `JSObject` with 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, `var` declarations, and functions.
#### Types
- Supports mapping basic JS types to Dart `js_interop` types.
- `never` type returned from a const declaration, function, readonly property or method has the declaration annotated with [`@doNotStore`](https://pub.dev/documentation/meta/latest/meta/doNotStore-constant.html).
- Supports automatically mapping web types to `package:web` types
- 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 `null` or `undefined` equals `never`
- 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 `JSFunction` overriding the `call` method. This allows for a stronger type signature than just `JSFunction`. While closures leave their calls as `external`, construct signatures just redirect to the class constructor.
- Generic types are represented as normal Dart generics, and they are constrained by `JSAny` by default.
- `typeof` declarations 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 `keyof` correctly).
- Function: `JSFunction`
- Otherwise, the extension type representation of the type that it refers to is used.
- `keyof` declarations are represented as unions of the keys for the operand type.
#### Other
- 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 `@deprecated` and `@experimental`
## Web IDL Definitions
To generate Dart interfaces for a given `.idl` file, run the following at the root of this package:
```shell
dart bin/update_idl_bindings.dart
```
If 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:
```shell
dart bin/update_idl_bindings.dart
```
### Update to the latest Web IDL versions and regenerate
To re-generate the package from newer IDL versions, you can either run:
```shell
dart bin/update_idl_bindings.dart --update
```
or, manually edit `lib/src/package.json` to use specific IDL versions, and
re-run `update_idl_bindings.dart`.
#### Updating the dartdoc info from MDN
package:web's dartdoc comments come from the
[MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web) project. In order
to update to the latest version of the documentation, run:
```shell
dart bin/scrape_mdn.dart
```
That 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.
### Generation conventions
The generator scripts use a number of conventions to consistently handle Web IDL
definitions:
#### Interfaces
- Interfaces are emitted as extension types that wrap and implement `JSObject`.
- Interface inheritance is maintained using `implements` between 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.
#### Types
- Generic types include the generic in the case of `JSArray` and `JSPromise`.
- 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 `String` instead of `JSString`.
- 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.
#### Compatibility
- The generator uses the
[MDN compatibility data](https://github.com/mdn/browser-compat-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.
### Generate all bindings
To ignore the compatibility data and emit all members, run:
```shell
dart bin/update_idl_bindings.dart --generate-all
```
This is useful if you want to avoid having to write bindings manually for some
experimental and non-standard APIs.
## Web IDL versions
Based on:
<!-- START updated by bin/update_idl_bindings.dart. Do not modify by hand -->
| Item | Version |
| --- | --: |
| `@webref/css` | [6.20.3](https://www.npmjs.com/package/@webref/css/v/6.20.3) |
| `@webref/elements` | [2.4.0](https://www.npmjs.com/package/@webref/elements/v/2.4.0) |
| `@webref/idl` | [3.60.1](https://www.npmjs.com/package/@webref/idl/v/3.60.1) |
<!-- END updated by bin/update_idl_bindings.dart. Do not modify by hand -->