Skip to content
37 changes: 37 additions & 0 deletions web_generator/lib/src/ast/declarations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,40 @@ class ParameterDeclaration {
..type = type.emit(TypeOptions(nullable: optional)));
}
}

class TypeAliasDeclaration extends NamedDeclaration
implements ExportableDeclaration {
@override
final String name;

final List<GenericType> typeParameters;

final Type type;

@override
final String? dartName;

@override
bool exported;

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

TypeAliasDeclaration(
{required this.name,
this.typeParameters = const [],
required this.type,
required this.exported})
: dartName = null;

@override
TypeDef emit([DeclarationOptions? options]) {
options ??= DeclarationOptions();

return TypeDef((t) => t
..name = name
..types
.addAll(typeParameters.map((t) => t.emit(options?.toTypeOptions())))
..definition = type.emit(options?.toTypeOptions()));
}
}
9 changes: 5 additions & 4 deletions web_generator/lib/src/ast/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:code_builder/code_builder.dart';
import '../interop_gen/namer.dart';
import 'base.dart';
import 'helpers.dart';

class ReferredType<T extends Declaration> extends Type {
@override
Expand All @@ -23,10 +24,10 @@ class ReferredType<T extends Declaration> extends Type {
this.typeParams = const []});

@override
Reference emit([TypeOptions? options]) {
// TODO: implement emit
throw UnimplementedError();
}
Reference emit([TypeOptions? options]) => TypeReference((t) => t
..symbol = name
..types.addAll(typeParams.map((t) => getJSTypeAlternative(t).emit(options)))
..isNullable = options?.nullable);
}

// TODO(https://github.com/dart-lang/web/issues/385): Implement Support for UnionType (including implementing `emit`)
Expand Down
28 changes: 27 additions & 1 deletion web_generator/lib/src/interop_gen/transform/transformer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ class Transformer {
final decs = _transformVariable(node as TSVariableStatement);
nodeMap.addAll({for (final d in decs) d.id.toString(): d});
default:
final Declaration decl = switch (node.kind) {
final decl = switch (node.kind) {
TSSyntaxKind.FunctionDeclaration =>
_transformFunction(node as TSFunctionDeclaration),
TSSyntaxKind.TypeAliasDeclaration =>
_transformTypeAlias(node as TSTypeAliasDeclaration),
_ => throw Exception('Unsupported Declaration Kind: ${node.kind}')
};
// ignore: dead_code This line will not be dead in future decl additions
Expand Down Expand Up @@ -91,6 +93,30 @@ class Transformer {
return declarations?.toDart.first;
}

TypeAliasDeclaration _transformTypeAlias(TSTypeAliasDeclaration typealias) {
final name = typealias.name.text;

final modifiers = typealias.modifiers?.toDart;
final isExported = modifiers?.any((m) {
return m.kind == TSSyntaxKind.ExportKeyword;
}) ??
false;

final typeParams = typealias.typeParameters?.toDart;

final type = typealias.type;

return TypeAliasDeclaration(
name: name,
// TODO: Can we find a way not to make the types be JS types
// by default if possible. Leaving this for now,
// so that using such typealiases in generics does not break
type: getJSTypeAlternative(_transformType(type)),
typeParameters:
typeParams?.map(_transformTypeParamDeclaration).toList() ?? [],
exported: isExported);
}

FunctionDeclaration _transformFunction(TSFunctionDeclaration function) {
final name = function.name.text;

Expand Down
10 changes: 10 additions & 0 deletions web_generator/lib/src/js/typescript.types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extension type const TSSyntaxKind._(num _) {
static const TSSyntaxKind InterfaceDeclaration = TSSyntaxKind._(264);
static const TSSyntaxKind FunctionDeclaration = TSSyntaxKind._(262);
static const TSSyntaxKind ExportDeclaration = TSSyntaxKind._(278);
static const TSSyntaxKind TypeAliasDeclaration = TSSyntaxKind._(265);
static const TSSyntaxKind Parameter = TSSyntaxKind._(169);

/// keywords
Expand Down Expand Up @@ -136,6 +137,15 @@ extension type TSFunctionDeclaration._(JSObject _) implements TSDeclaration {
external TSNodeArray<TSNode> get modifiers;
}

@JS('TypeAliasDeclaration')
extension type TSTypeAliasDeclaration._(JSObject _)
implements TSDeclaration, TSStatement {
external TSNodeArray<TSNode>? get modifiers;
external TSNodeArray<TSTypeParameterDeclaration>? get typeParameters;
external TSIdentifier get name;
external TSTypeNode get type;
}

@JS('ParameterDeclaration')
extension type TSParameterDeclaration._(JSObject _) implements TSDeclaration {
external TSNode get name;
Expand Down
25 changes: 25 additions & 0 deletions web_generator/test/integration/interop_gen/typealias_expected.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:js_interop' as _i1;

typedef Username = _i1.JSString;
typedef Age = _i1.JSNumber;
typedef IsActive = _i1.JSBoolean;
typedef Tags = _i1.JSArray<_i1.JSString>;
typedef List<T extends _i1.JSAny?> = _i1.JSArray<T>;
typedef Box<T extends _i1.JSAny?> = _i1.JSArray<_i1.JSArray<T>>;
typedef PromisedArray<U extends _i1.JSAny?, T extends _i1.JSArray<U>>
= _i1.JSPromise<T>;
@_i1.JS()
external Username get username;
@_i1.JS()
external Age get age;
@_i1.JS()
external _i1.JSArray<Tags> get tagArray;
@_i1.JS()
external List<Username> get users;
@_i1.JS()
external Box<_i1.JSNumber> get matrix;
@_i1.JS()
external PromisedArray<_i1.JSString, _i1.JSArray<_i1.JSString>> fetchNames();
@_i1.JS()
external String isUserActive(IsActive status);
14 changes: 14 additions & 0 deletions web_generator/test/integration/interop_gen/typealias_input.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export type Username = string;
export type Age = number;
export type IsActive = boolean;
export type Tags = string[];
export type List<T> = T[];
export type Box<T> = Array<Array<T>>;
export type PromisedArray<U, T extends Array<U>> = Promise<T>;
export declare const username: Username;
export declare const age: Age;
export declare const tagArray: Tags[];
export declare const users: List<Username>;
export declare const matrix: Box<number>;
export declare function fetchNames(): PromisedArray<string, string[]>;
export declare function isUserActive(status: IsActive): string;
Loading