Skip to content
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
36 changes: 14 additions & 22 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.4.1"
charcode:
dependency: transitive
description:
Expand Down Expand Up @@ -205,10 +205,10 @@ packages:
dependency: transitive
description:
name: coverage
sha256: "9086475ef2da7102a0c0a4e37e1e30707e7fb7b6d28c209f559a9c5f8ce42016"
sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.15.0"
crypto:
dependency: transitive
description:
Expand Down Expand Up @@ -445,14 +445,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation:
dependency: transitive
description:
Expand Down Expand Up @@ -529,18 +521,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.13.0"
meta:
dependency: transitive
description:
Expand Down Expand Up @@ -918,26 +910,26 @@ packages:
dependency: transitive
description:
name: test
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
sha256: "54c516bbb7cee2754d327ad4fca637f78abfc3cbcc5ace83b3eda117e42cd71a"
url: "https://pub.dev"
source: hosted
version: "1.26.3"
version: "1.29.0"
test_api:
dependency: transitive
description:
name: test_api
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted
version: "0.7.7"
version: "0.7.9"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
sha256: "394f07d21f0f2255ec9e3989f21e54d3c7dc0e6e9dbce160e5a9c1a6be0e2943"
url: "https://pub.dev"
source: hosted
version: "0.6.12"
version: "0.6.15"
typed_data:
dependency: transitive
description:
Expand Down
28 changes: 28 additions & 0 deletions vaden/example/lib/src/controllers/order_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:example/src/dtos/order_dto.dart';
import 'package:example/src/enums/order_status.dart';
import 'package:vaden/vaden.dart';

@Api(tag: 'orders', description: 'Order operations')
@Controller('/orders')
class OrderController {
@Get('/')
List<OrderDto> getAll() {
return [
OrderDto(
id: '1',
status: OrderStatus.pending,
history: [OrderStatus.pending],
),
];
}

@Get('/by-status/<status>')
List<OrderDto> getByStatus(@Param() String status) {
return [];
}

@Post('/')
OrderDto create(@Body() OrderDto order) {
return order;
}
}
15 changes: 15 additions & 0 deletions vaden/example/lib/src/dtos/order_dto.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:example/src/enums/order_status.dart';
import 'package:vaden/vaden.dart';

@DTO()
class OrderDto {
final String id;
final OrderStatus status;
final List<OrderStatus> history;

OrderDto({
required this.id,
required this.status,
required this.history,
});
}
7 changes: 7 additions & 0 deletions vaden/example/lib/src/enums/order_status.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
enum OrderStatus {
pending,
processing,
shipped,
delivered,
cancelled,
}
6 changes: 6 additions & 0 deletions vaden/example/lib/src/enums/product_category.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
enum ProductCategory {
electronics,
clothing,
food,
books,
}
7 changes: 4 additions & 3 deletions vaden/example/lib/src/hello_controller.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';

import 'package:example/src/enums/product_category.dart';
import 'package:example/src/product_dto.dart';
import 'package:vaden/vaden.dart';

Expand Down Expand Up @@ -33,9 +34,9 @@ class HelloController {
@Get('/object')
List<ProductDto> object() {
return [
ProductDto(name: 'Product 1', price: 100.0),
ProductDto(name: 'Product 2', price: 200.0),
ProductDto(name: 'Product 3', price: 300.0),
ProductDto(name: 'Product 1', price: 100.0, category: ProductCategory.electronics),
ProductDto(name: 'Product 2', price: 200.0, category: ProductCategory.clothing),
ProductDto(name: 'Product 3', price: 300.0, category: ProductCategory.food),
];
}

Expand Down
8 changes: 7 additions & 1 deletion vaden/example/lib/src/product_dto.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import 'package:example/src/enums/product_category.dart';
import 'package:vaden/vaden.dart';

@DTO()
class ProductDto {
final String name;
final double price;
final ProductCategory category;

ProductDto({required this.name, required this.price});
ProductDto({
required this.name,
required this.price,
required this.category,
});
}
82 changes: 82 additions & 0 deletions vaden_class_scanner/lib/src/setups/initial.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:build/build.dart';
import 'package:dart_style/dart_style.dart';
import 'package:path/path.dart' as p;
Expand Down Expand Up @@ -191,6 +192,8 @@ ComponentRegistration _selectComponent({
priority = ComponentPriority.configuration;
} else if (controllerChecker.hasAnnotationOf(classElement)) {
bodyBuffer.writeln(controllerSetup(classElement));
_collectFieldTypeImports(classElement, importSet);
_collectMethodParamTypeImports(classElement, importSet);
priority = ComponentPriority.controller;
} else if (apiClientBuffer != null &&
apiClientChecker.hasAnnotationOf(classElement)) {
Expand All @@ -204,6 +207,7 @@ ComponentRegistration _selectComponent({
priority = ComponentPriority.component;
} else if (dtoChecker.hasAnnotationOf(classElement)) {
dtoBuffer.writeln(dtoSetup(classElement));
_collectFieldTypeImports(classElement, importSet);
priority = ComponentPriority.other;
} else if (controllerAdviceChecker.hasAnnotationOf(classElement)) {
final (adviceBody, imports) = controllerAdviceSetup(classElement);
Expand Down Expand Up @@ -344,3 +348,81 @@ Future<void> writeAndFormatApplication(String text, BuildStep buildStep) async {
await buildStep.writeAsString(outputId, text);
}
}

/// Adds import URIs for non-primitive types referenced by the fields of
/// [classElement] (and its supertypes) that are not already covered by
/// annotation-based scanning. This handles enums and other types defined
/// in separate files.
void _collectFieldTypeImports(
ClassElement classElement,
Set<String> importSet,
) {
ClassElement? current = classElement;
while (current != null) {
for (final field in current.fields) {
if (field.isSynthetic || field.isStatic || field.isPrivate) continue;
_addTypeImport(field.type, importSet);
}
final superType = current.supertype;
if (superType == null || superType.isDartCoreObject) break;
current = superType.element as ClassElement?;
}
}

/// Adds import URIs for non-primitive types referenced by method parameters
/// of [classElement], covering @Param, @Query and @Body enum types in
/// controllers. Traverses supertypes to match the same method resolution
/// used by [controllerSetup].
void _collectMethodParamTypeImports(
ClassElement classElement,
Set<String> importSet,
) {
final visited = <String>{};

void collectFromMethods(InterfaceElement element) {
for (final method in element.methods) {
if (method.isStatic || method.isPrivate) continue;
final name = method.name;
if (name == null || !visited.add(name)) continue;
for (final param in method.formalParameters) {
_addTypeImport(param.type, importSet);
}
_addTypeImport(method.returnType, importSet);
}
}

collectFromMethods(classElement);

for (final supertype in classElement.allSupertypes) {
if (supertype.element.name == 'Object') continue;
collectFromMethods(supertype.element);
}
}

/// Resolves the library URI for [type] and adds it to [importSet] if it is
/// a non-core type (enum, class, etc.) defined outside of dart:core.
void _addTypeImport(DartType type, Set<String> importSet) {
// Unwrap Future / FutureOr
if (type.isDartAsyncFuture || type.isDartAsyncFutureOr) {
if (type is ParameterizedType && type.typeArguments.isNotEmpty) {
_addTypeImport(type.typeArguments.first, importSet);
}
return;
}

// Unwrap List / Set / Map type arguments
if (type is ParameterizedType && type.typeArguments.isNotEmpty) {
for (final arg in type.typeArguments) {
_addTypeImport(arg, importSet);
}
}

final element = type.element;
if (element == null) return;

// Skip dart:core types (int, String, bool, etc.)
final uri = element.library?.uri.toString() ?? '';
if (uri.isEmpty || uri.startsWith('dart:')) return;

importSet.add("'$uri';");
}