Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 124 additions & 12 deletions web_generator/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,133 @@
## What's this?

This package contains tools to generate
This package contains tools to generate Dart interfaces from TypeScript Declaration code 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.

### Regenerating the package

The tool to generate bindings is written in Dart, compiled to JavaScript, and
## Using this
The tools to generate bindings are written in Dart, compiled to JavaScript, and
run on Node.

To regenerate `web` bindings from the current IDL versions, run:
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,

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>` 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 defaults it 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
- For most cases, enums are represented without any external calls, and can have their rep type as Dart primitive types where possible
- If the value for an enum is not given, then the whole enum is treated as an external interop member, 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.
- Classes are generated as well as static methods that redirect to constructor calls.
- Namespaces nested inside the namespace are as well generated as static getters on the
- 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. 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 more typing as opposed to just `JSFunction`. While closures have their calls as `external`, construct signatures were redirect calls to the class constructor itself.
- 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`
- Rest: The extension type representation of the type that it refers to.
- `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

## 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
### Update to the latest Web IDL versions and regenerate

To re-generate the package from newer IDL versions, you can either run:

Expand All @@ -26,7 +138,7 @@ 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
#### 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
Expand All @@ -40,20 +152,20 @@ 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
### Generation conventions

The generator scripts use a number of conventions to consistently handle Web IDL
definitions:

### Interfaces
#### 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
#### Types

- Generic types include the generic in the case of `JSArray` and `JSPromise`.
- Enums are typedef'd to `String`.
Expand All @@ -67,15 +179,15 @@ definitions:
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
#### 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
### Generate all bindings

To ignore the compatibility data and emit all members, run:

Expand Down
1 change: 1 addition & 0 deletions web_generator/bin/gen_interop_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ $_usage''');
await compileDartMain();
}

// TODO(nikeokoronkwo): Multi-file input
final inputFile = argResult.rest.firstOrNull;
final outputFile = argResult['output'] as String? ??
p.join(p.current, inputFile?.replaceAll('.d.ts', '.dart'));
Expand Down
2 changes: 1 addition & 1 deletion web_generator/lib/src/dart_main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import 'js/filesystem_api.dart';
import 'js/node.dart';
import 'util.dart';

// Generates DOM bindings for Dart.
// Generates DOM and JS interop bindings for Dart.

// TODO(joshualitt): Use static interop methods for JSArray and JSPromise.
// TODO(joshualitt): Find a way to generate bindings for JS builtins. This will
Expand Down