Skip to content

[interop] Add Support for Function Declarations #392

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
169 changes: 0 additions & 169 deletions web_generator/lib/src/ast.dart

This file was deleted.

75 changes: 75 additions & 0 deletions web_generator/lib/src/ast/base.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// 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.

import 'package:code_builder/code_builder.dart';

import '../interop_gen/namer.dart';
import 'types.dart';

class GlobalOptions {
static int variardicArgsCount = 4;
static bool shouldEmitJsTypes = false;
}

class Options {}

class DeclarationOptions extends Options {
DeclarationOptions();

TypeOptions toTypeOptions({bool nullable = false}) =>
TypeOptions(nullable: nullable);
}

class TypeOptions extends Options {
bool nullable;

TypeOptions({this.nullable = false});
}

class ASTOptions {
bool parameter;
bool emitJSTypes;
int variardicArgsCount;

ASTOptions(
{this.parameter = false,
this.variardicArgsCount = 4,
this.emitJSTypes = false});
}

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

Spec emit([Options? options]);

Node();
}

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

@override
Spec emit([covariant DeclarationOptions? options]);
}

abstract class NamedDeclaration extends Declaration {
ReferredType asReferredType([List<Type>? typeArgs]) =>
ReferredType(name: name, declaration: this, typeParams: typeArgs ?? []);
}

abstract interface class ExportableDeclaration extends Declaration {
/// Whether this declaration is exported.
bool get exported;
}

abstract class Type extends Node {
@override
String? dartName;

@override
Reference emit([covariant TypeOptions? options]);
}
123 changes: 123 additions & 0 deletions web_generator/lib/src/ast/builtin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// 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.

// ignore_for_file: non_constant_identifier_names

import 'package:code_builder/code_builder.dart';

import '../interop_gen/namer.dart';
import 'base.dart';

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

final List<Type> typeParams;

/// 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;

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

@override
ID get id => ID(type: 'type', name: name);

@override
String? get dartName => null;

@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())))
..url = fromDartJSInterop ? 'dart:js_interop' : null
..isNullable = isNullable ?? options!.nullable);
}

static final BuiltinType $voidType = BuiltinType(name: 'void');
static final BuiltinType anyType =
BuiltinType(name: 'JSAny', fromDartJSInterop: true, isNullable: true);

static BuiltinType primitiveType(PrimitiveType typeIdentifier,
{bool? shouldEmitJsType,
bool? isNullable,
List<Type> typeParams = const []}) {
shouldEmitJsType ??= GlobalOptions.shouldEmitJsTypes;
return switch (typeIdentifier) {
PrimitiveType.int => shouldEmitJsType
? BuiltinType(
name: 'JSNumber', fromDartJSInterop: true, isNullable: isNullable)
: BuiltinType(name: 'int', isNullable: isNullable),
PrimitiveType.num => shouldEmitJsType
? BuiltinType(
name: 'JSNumber', fromDartJSInterop: true, isNullable: isNullable)
: BuiltinType(name: 'num', isNullable: isNullable),
PrimitiveType.double => shouldEmitJsType
? BuiltinType(
name: 'JSNumber', fromDartJSInterop: true, isNullable: isNullable)
: BuiltinType(name: 'double', isNullable: isNullable),
PrimitiveType.boolean => shouldEmitJsType
? BuiltinType(
name: 'JSBoolean',
fromDartJSInterop: true,
isNullable: isNullable)
: BuiltinType(name: 'bool', isNullable: isNullable),
PrimitiveType.string => shouldEmitJsType
? BuiltinType(
name: 'JSString', fromDartJSInterop: true, isNullable: isNullable)
: BuiltinType(name: 'String', isNullable: isNullable),
PrimitiveType.$void => $voidType,
PrimitiveType.any => anyType,
PrimitiveType.object => BuiltinType(
name: 'JSObject', fromDartJSInterop: true, isNullable: isNullable),
PrimitiveType.unknown =>
BuiltinType(name: 'JSAny', fromDartJSInterop: true, isNullable: true),
PrimitiveType.undefined =>
BuiltinType(name: 'JSAny', fromDartJSInterop: true, isNullable: true),
PrimitiveType.array => BuiltinType(
name: 'JSArray',
typeParams: [typeParams.single],
fromDartJSInterop: true,
isNullable: isNullable),
PrimitiveType.promise => BuiltinType(
name: 'JSPromise',
typeParams: [typeParams.single],
fromDartJSInterop: true,
isNullable: isNullable),
PrimitiveType.function => BuiltinType(
name: 'JSFunction', fromDartJSInterop: true, isNullable: isNullable),
};
}
}

enum PrimitiveType {
int,
num,
double,
boolean,
string,
$void,
any,
object,
unknown,
undefined,
array,
promise,
function
}
Loading