Skip to content

Use extension types and generics internally #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 8 additions & 14 deletions tool/generator/filesystem_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,25 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// TODO(srujzs): Remove this workaround once we use an SDK version that contains
// https://github.com/dart-lang/sdk/issues/54801.
@JS()
library;

import 'dart:js_interop';

@JS()
external FileSystem get fs;

@JS()
@anonymous
@staticInterop
class JSMkdirOptions {
extension type JSMkdirOptions._(JSObject _) implements JSObject {
external factory JSMkdirOptions({JSBoolean? recursive});
}

@JS()
@anonymous
@staticInterop
class JSReadFileOptions {
extension type JSReadFileOptions._(JSObject _) implements JSObject {
external factory JSReadFileOptions({JSString? encoding});
}

@JS()
@staticInterop
class FileSystem {}

// TODO(joshualitt): Replace `void` with `JSVoid`
extension FileSystemExtension on FileSystem {
extension type FileSystem._(JSObject _) implements JSObject {
external JSBoolean existsSync(JSString path);

@JS('mkdirSync')
Expand Down
17 changes: 9 additions & 8 deletions tool/generator/generate_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ import 'dart:js_interop';

import 'translator.dart';
import 'util.dart';
import 'webidl_api.dart' as webidl;
import 'webref_css_api.dart';
import 'webref_idl_api.dart';

/// Generate CSS property names for setting / getting CSS properties in JS.
Future<List<String>> _generateCSSStyleDeclarations() async {
final cssStyleDeclarations = <String>{};
final array = objectEntries(await css.listAll().toDart as JSObject);
final array = objectEntries(await css.listAll().toDart);
for (var i = 0; i < array.length; i++) {
final entry = array[i] as JSArray;
final data = entry[1] as CSSEntries;
final entry = array[i] as JSArray<CSSEntries>;
final data = entry[1];
final properties = data.properties;
if (properties != null) {
for (var j = 0; j < properties.length; j++) {
final property = properties[j] as CSSEntry;
final property = properties[j];
// There are three cases for [styleDeclaration]:
// 1) Length == 1, a single word CSS property.
// 2) Length == 2, a kebab case property + a camel case property.
Expand All @@ -32,7 +33,7 @@ Future<List<String>> _generateCSSStyleDeclarations() async {
}
// For now we ignore browser specific properties.
if (length == 3) continue;
final style = (styleDeclaration[length - 1] as JSString).toDart;
final style = styleDeclaration[length - 1].toDart;
if (style.contains('-')) {
throw Exception('Unexpected style declaration $styleDeclaration');
}
Expand All @@ -49,11 +50,11 @@ Future<TranslationResult> generateBindings(
final cssStyleDeclarations = await _generateCSSStyleDeclarations();
final translator =
Translator(packageRoot, librarySubDir, cssStyleDeclarations);
final array = objectEntries(await idl.parseAll().toDart as JSObject);
final array = objectEntries(await idl.parseAll().toDart);
for (var i = 0; i < array.length; i++) {
final entry = array[i] as JSArray;
final entry = array[i] as JSArray<JSAny?>;
final shortname = (entry[0] as JSString).toDart;
final ast = entry[1] as JSArray;
final ast = entry[1] as JSArray<webidl.Node>;
translator.collect(shortname, ast);
}
translator.setOrUpdateInterfacelikes();
Expand Down
16 changes: 8 additions & 8 deletions tool/generator/translator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -287,21 +287,21 @@ class _Parameter {
class _OverridableMember {
final List<_Parameter> parameters = [];

_OverridableMember(JSArray rawParameters) {
_OverridableMember(JSArray<idl.Argument> rawParameters) {
for (var i = 0; i < rawParameters.length; i++) {
parameters.add(_Parameter(rawParameters[i] as idl.Argument));
parameters.add(_Parameter(rawParameters[i]));
}
}

void _processParameters(JSArray thoseParameters) {
void _processParameters(JSArray<idl.Argument> thoseParameters) {
// Assume if we have extra arguments beyond what was provided in some other
// method, that these are all optional.
final thatLength = thoseParameters.length;
for (var i = thatLength; i < parameters.length; i++) {
parameters[i].isOptional = true;
}
for (var i = 0; i < thatLength; i++) {
final argument = thoseParameters[i] as idl.Argument;
final argument = thoseParameters[i];
if (i >= parameters.length) {
// We assume these parameters must be optional, regardless of what the
// IDL says.
Expand Down Expand Up @@ -361,9 +361,9 @@ class _PartialInterfacelike {
return partialInterfacelike;
}

void _processMembers(JSArray nodeMembers) {
void _processMembers(JSArray<idl.Member> nodeMembers) {
for (var i = 0; i < nodeMembers.length; i++) {
final member = nodeMembers[i] as idl.Member;
final member = nodeMembers[i];
final type = member.type;
switch (type) {
case 'constructor':
Expand Down Expand Up @@ -532,14 +532,14 @@ class Translator {
}
}

void collect(String shortName, JSArray ast) {
void collect(String shortName, JSArray<idl.Node> ast) {
final libraryPath = '$_librarySubDir/${shortName.kebabToSnake}.dart';
assert(!_libraries.containsKey(libraryPath));

final library = _Library(this, '$packageRoot/$libraryPath');

for (var i = 0; i < ast.length; i++) {
library.add(ast[i] as idl.Node);
library.add(ast[i]);
}

if (_shouldGenerate(shortName, library)) {
Expand Down
7 changes: 4 additions & 3 deletions tool/generator/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import 'filesystem_api.dart';

// TODO(joshualitt): Let's find a better place for these.
@JS('Object.entries')
external JSArray objectEntries(JSObject o);
external JSArray<JSAny?> objectEntries(JSObject o);

extension JSArrayExtension on JSArray {
external JSAny? operator [](int i);
// TODO(srujzs): Remove once this is in dart:js_interop.
extension JSArrayExtension<T extends JSAny?> on JSArray<T> {
external T operator [](int i);
external int get length;
}

Expand Down
122 changes: 24 additions & 98 deletions tool/generator/webidl_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@

import 'dart:js_interop';

@JS()
@staticInterop
class IDLType {}

extension IDLTypeExtension on IDLType {
extension type IDLType._(JSObject _) implements JSObject {
external String? get type;
external String get generic;
external JSAny get idlType;
Expand All @@ -18,21 +14,13 @@ extension IDLTypeExtension on IDLType {

/// The abstract node interface in the IDL AST. All nodes that can occur at the
/// root of the IDL inherit from [Node].
@JS()
@staticInterop
class Node {}

extension NodeExtension on Node {
extension type Node._(JSObject _) implements JSObject {
external String get type;
}

/// The abstract node interface for named nodes in the IDL. Most root nodes have
/// names, with the exception of `includes`.
@JS()
@staticInterop
class Named extends Node {}

extension NamedExtension on Named {
extension type Named._(JSObject _) implements Node {
external String get name;
}

Expand All @@ -43,69 +31,39 @@ extension NamedExtension on Named {
/// * callback interface
/// * dictionary
/// To disambiguate, use the `type` getter.
@JS()
@staticInterop
class Interfacelike extends Named {}

extension InterfaceExtension on Interfacelike {
extension type Interfacelike._(JSObject _) implements Named {
external bool get partial;
external JSArray get members;
external JSArray<Member> get members;
external String? get inheritance;
}

@JS()
@staticInterop
class Callback extends Named {}

extension CallbackExtension on Callback {
extension type Callback._(JSObject _) implements Named {
external IDLType get idlType;
external JSArray get arguments;
external JSArray<Argument> get arguments;
}

@JS()
@staticInterop
class EnumValue {}

extension EnumValueExtension on EnumValue {
extension type EnumValue._(JSObject _) implements JSObject {
external String get type;
external String get value;
}

@JS()
@staticInterop
class Enum extends Named {}

@JS()
@staticInterop
class Typedef extends Named {}
extension type Enum._(JSObject _) implements Named {}

extension TypedefExtension on Typedef {
extension type Typedef._(JSObject _) implements Named {
external IDLType get idlType;
}

@JS()
@staticInterop
class Includes extends Node {}

extension IncludesExtension on Includes {
extension type Includes._(JSObject _) implements Node {
external String get target;
external String get includes;
}

/// All members inherit from the [Member] node.
@JS()
@staticInterop
class Member {}

extension MemberExtension on Member {
extension type Member._(JSObject _) implements JSObject {
external String get type;
}

@JS()
@staticInterop
class Argument {}

extension ArgumentExtension on Argument {
extension type Argument._(JSObject _) implements JSObject {
external String get type;
@JS('default')
external Value? get defaultValue;
Expand All @@ -115,63 +73,39 @@ extension ArgumentExtension on Argument {
external String get name;
}

@JS()
@staticInterop
class Operation extends Member {}

extension OperationExtension on Operation {
extension type Operation._(JSObject _) implements Member {
external String get special;
external IDLType get idlType;
external String get name;
external JSArray get arguments;
external JSArray<Argument> get arguments;
}

@JS()
@staticInterop
class Constructor extends Member {}

extension ConstructorExtension on Constructor {
external JSArray get arguments;
extension type Constructor._(JSObject _) implements Member {
external JSArray<Argument> get arguments;
}

@JS()
@staticInterop
class Attribute extends Member {}

extension AttributeExtension on Attribute {
extension type Attribute._(JSObject _) implements Member {
external String get special;
external bool get readonly;
external IDLType get idlType;
external String get name;
}

@JS()
@staticInterop
class Field extends Member {}

extension FieldExtension on Field {
extension type Field._(JSObject _) implements Member {
external String get name;
external bool get required;
external IDLType get idlType;
@JS('default')
external Value? get defaultValue;
}

@JS()
@staticInterop
class Value {}

extension ValueExtension on Value {
extension type Value._(JSObject _) implements JSObject {
external String get type;
external JSAny? get value;
external bool? get negative;
}

@JS()
@staticInterop
class Constant extends Member {}

extension ConstantExtension on Constant {
extension type Constant._(JSObject _) implements Member {
external IDLType get idlType;
external String get name;
external Value get value;
Expand All @@ -182,23 +116,15 @@ extension ConstantExtension on Constant {
/// * async iterable<>
/// * maplike<>
/// * setlike<>
@JS()
@staticInterop
class MemberDeclaration {}

extension MemberDeclarationExtension on MemberDeclaration {
extension type MemberDeclaration._(JSObject _) implements JSObject {
external String get type;
external IDLType get idlType;
external bool get readonly;
external bool get async;
external JSArray get arguments;
external JSArray<Argument> get arguments;
}

@JS()
@staticInterop
class EOF {}

extension EOFExtension on EOF {
extension type EOF._(JSObject _) implements JSObject {
external String get type;
external String get value;
}
Loading