Skip to content

[interop] Add Support for Anonymous Declarations #434

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 24 commits into from
Aug 15, 2025
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1c76d12
wip: union types
nikeokoronkwo Aug 1, 2025
d79c2cf
wip: completed anonymous unions
nikeokoronkwo Aug 2, 2025
38b3aab
implemented JS Tuple
nikeokoronkwo Aug 2, 2025
cb90943
completed nullability support for `undefined` and `null`
nikeokoronkwo Aug 2, 2025
37e0d1a
Merge branch 'main' into interop/anonymous
nikeokoronkwo Aug 6, 2025
0b943e7
wip: object decl
nikeokoronkwo Aug 6, 2025
e7535a4
implemented anonymous objects
nikeokoronkwo Aug 6, 2025
c49ce6c
added support for closures and constructors
nikeokoronkwo Aug 7, 2025
f1a9e1c
wip: type hierarchy
nikeokoronkwo Aug 7, 2025
7f0a2e0
implemented sub type deduction
nikeokoronkwo Aug 7, 2025
f57165c
added type generics to union types
nikeokoronkwo Aug 7, 2025
49aa015
changed `.reduce` to `.fold`
nikeokoronkwo Aug 7, 2025
574250f
resolved newline and license headers
nikeokoronkwo Aug 8, 2025
283ab5d
isNullable updates and renamed `DeclarationAssociatedType`
nikeokoronkwo Aug 8, 2025
4a9bca6
updated algorithm to use LCA via Topological Ordering
nikeokoronkwo Aug 11, 2025
78a535f
resolved some more comments
nikeokoronkwo Aug 12, 2025
5421359
rm hasher_test
nikeokoronkwo Aug 12, 2025
f92ffc9
resolved some more comments
nikeokoronkwo Aug 12, 2025
9944b7f
refactored tuple generation (common types) and more
nikeokoronkwo Aug 12, 2025
c665449
added LCA test
nikeokoronkwo Aug 14, 2025
3dae04e
removed stray prints
nikeokoronkwo Aug 14, 2025
6632bc0
Merge branch 'main' into interop/anonymous
nikeokoronkwo Aug 14, 2025
5326ae0
added doc support and resolved merge
nikeokoronkwo Aug 14, 2025
552a461
updated documentation formatting using formatting.dart
nikeokoronkwo Aug 15, 2025
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
2 changes: 2 additions & 0 deletions web_generator/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ analyzer:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
comment_references: ignore

linter:
rules:
Expand Down
40 changes: 34 additions & 6 deletions web_generator/lib/src/ast/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ class ASTOptions {
}

sealed class Node {
String? get name;
abstract final ID id;
String? get dartName;

Expand All @@ -55,7 +54,6 @@ sealed class Node {
}

abstract class Declaration extends Node {
@override
String get name;

@override
Expand All @@ -66,11 +64,19 @@ abstract class NamedDeclaration extends Declaration {
@override
abstract String name;

abstract Documentation? documentation;

ReferredType asReferredType([List<Type>? typeArgs, String? url]) =>
ReferredType asReferredType(
[List<Type>? typeArgs, bool isNullable = false, String? url]) =>
ReferredType(
name: name, declaration: this, typeParams: typeArgs ?? [], url: url);
name: name,
declaration: this,
typeParams: typeArgs ?? [],
url: url,
isNullable: isNullable);
}

abstract interface class DocumentedDeclaration {
/// The documentation associated with the given declaration
abstract Documentation? documentation;
}

abstract interface class ExportableDeclaration extends Declaration {
Expand All @@ -88,8 +94,20 @@ abstract class Type extends Node {
@override
String? dartName;

/// Whether the given type is nullable or not
/// (unioned with `undefined` or `null`)
abstract bool isNullable;

@override
Reference emit([covariant TypeOptions? options]);

@override
bool operator ==(Object other) {
return other is Type && id == other.id;
}

@override
int get hashCode => Object.hashAll([id]);
}

abstract class FieldDeclaration extends NamedDeclaration {
Expand All @@ -106,6 +124,12 @@ abstract class CallableDeclaration extends NamedDeclaration {

enum DeclScope { private, protected, public }

abstract class DeclarationType<T extends Declaration> extends Type {
T get declaration;

String get declarationName;
}

class ParameterDeclaration {
final String name;

Expand All @@ -127,3 +151,7 @@ class ParameterDeclaration {
..type = type.emit(TypeOptions(nullable: optional)));
}
}

abstract class NamedType extends Type {
String get name;
}
38 changes: 20 additions & 18 deletions web_generator/lib/src/ast/builtin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import 'base.dart';

/// A built in type supported by `dart:js_interop` or by this library
/// (with generated declarations)
class BuiltinType extends Type {
class BuiltinType extends NamedType {
@override
final String name;

Expand All @@ -21,15 +21,15 @@ class BuiltinType extends Type {
/// Whether the given type is present in "dart:js_interop"
final bool fromDartJSInterop;

// TODO(nikeokoronkwo): Types in general should have an `isNullable`
// property on them to indicate nullability for Dart generated code.
final bool? isNullable;
@override
bool isNullable;

BuiltinType(
{required this.name,
this.typeParams = const [],
this.fromDartJSInterop = false,
this.isNullable});
bool? isNullable})
: isNullable = isNullable ?? false;

@override
ID get id => ID(type: 'type', name: name);
Expand All @@ -39,16 +39,14 @@ class BuiltinType extends Type {

@override
Reference emit([TypeOptions? options]) {
options ??= TypeOptions();

return TypeReference((t) => t
..symbol = name
..types.addAll(typeParams
// if there is only one type param, and it is void, ignore
.where((p) => typeParams.length != 1 || p != $voidType)
.map((p) => p.emit(TypeOptions())))
.map((p) => p.emit(options)))
..url = fromDartJSInterop ? 'dart:js_interop' : null
..isNullable = isNullable ?? options!.nullable);
..isNullable = isNullable || (options?.nullable ?? false));
}

static final BuiltinType $voidType = BuiltinType(name: 'void');
Expand Down Expand Up @@ -81,7 +79,10 @@ class BuiltinType extends Type {
name: 'JSString', fromDartJSInterop: true, isNullable: isNullable)
: BuiltinType(name: 'String', isNullable: isNullable),
PrimitiveType.$void || PrimitiveType.undefined => $voidType,
PrimitiveType.any || PrimitiveType.unknown => anyType,
PrimitiveType.any => (isNullable ?? false)
? anyType
: BuiltinType(name: 'JSAny', fromDartJSInterop: true),
PrimitiveType.unknown => anyType,
PrimitiveType.object => BuiltinType(
name: 'JSObject', fromDartJSInterop: true, isNullable: isNullable),
PrimitiveType.symbol => BuiltinType(
Expand Down Expand Up @@ -128,13 +129,14 @@ class BuiltinType extends Type {
}
}

class PackageWebType extends Type {
class PackageWebType extends NamedType {
@override
final String name;

final List<Type> typeParams;

final bool? isNullable;
@override
bool isNullable;

@override
ID get id => ID(type: 'type', name: name);
Expand All @@ -143,29 +145,29 @@ class PackageWebType extends Type {
String? get dartName => null;

PackageWebType._(
{required this.name, this.typeParams = const [], this.isNullable});
{required this.name,
this.typeParams = const [],
this.isNullable = false});

@override
Reference emit([TypeOptions? options]) {
options ??= TypeOptions();

// TODO: We can make this a shared function as it is called a lot
// between types
return TypeReference((t) => t
..symbol = name
..types.addAll(typeParams
// if there is only one type param, and it is void, ignore
.where((p) => typeParams.length != 1 || p != BuiltinType.$voidType)
.map((p) => p.emit(TypeOptions())))
.map((p) => p.emit(options)))
..url = 'package:web/web.dart'
..isNullable = isNullable ?? options!.nullable);
..isNullable = isNullable || (options?.nullable ?? false));
}

static PackageWebType parse(String name,
{bool? isNullable, List<Type> typeParams = const []}) {
return PackageWebType._(
name: renameMap.containsKey(name) ? renameMap[name]! : name,
isNullable: isNullable,
isNullable: isNullable ?? false,
typeParams: typeParams);
}
}
Expand Down
Loading