tree: c74bfd8d898a342e97193762fc2c892dfd508680 [path history] [tgz]
  1. bin/
  2. lib/
  3. test/
  4. analysis_options.yaml
  5. CHANGELOG.md
  6. LICENSE
  7. pubspec.yaml
  8. README.md
web_generator/README.md

What's this?

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.

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.

Requirements

Node.js

The web_generator requires Node.js v22 or newer. Older Node versions are not supported and may result in runtime failures.

TS Declarations

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 --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:

input: a.d.ts
output: b.d.ts
ts-config-file: tsconfig.json

The 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.yaml

Note that not all configuration options are direct mappings between the CLI and the configuration file.

Configuration File Reference

OptionDescriptionExample
nameThe name of the bindingsname: MyBindings
descriptionA description of the bindings (optional)description: My awesome bindings
preamblePreamble text to insert before the bindings (optional)preamble: |
// Generated. Do not edit.
inputA file (single string) or set of files (array of strings) passed into the generatorinput: bindings.d.ts
or
input:
- bindings.d.ts
outputThe output file or directory to write the bindings tooutput: lib/src/js
includeDeclarations 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 declarationsinclude:
- myNumber
language_versionThe Dart Language Version to use, usually for formatting (optional)language_version: 3.6.0
ts_configAn object consisting of TS Configurations following the tsconfig.json file schema used for configuring the TypeScript Program/Compiler (optional)ts_config:
compilerOptions:
target: es2020
ts_config_fileThe TS Configuration file (tsconfig.json) if any (optional)ts_config_file: tsconfig.json
generate_allInclude generating declarations for code that isn't exported. Defaults to falsegenerate_all: true
ignore_errorsIgnore source code warnings and errors (they will still be printed). Defaults to falseignore_errors: true
functions.varargsThe number of arguments that variable-argument functions should take. Defaults to 4functions:
varargs: 6

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.
  • 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.
  • 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:

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:

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:

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 project. In order to update to the latest version of the documentation, run:

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 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:

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:

ItemVersion
@webref/css6.20.3
@webref/elements2.4.0
@webref/idl3.60.1