diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ebaf94f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,22 @@ +version: 2 +updates: + - package-ecosystem: "pub" + directory: "package/inject_compile" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "package/inject_compile_generator" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "example/train" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "example/clean_architecture" + schedule: + interval: "daily" + - package-ecosystem: "pub" + directory: "example/coffee" + schedule: + interval: "daily" diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml new file mode 100644 index 0000000..eb5319a --- /dev/null +++ b/.github/workflows/dart.yml @@ -0,0 +1,32 @@ +name: Dart + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dart-lang/setup-dart@v1 + + - name: Install dependencies + run: dart pub get + + - name: Run code generation + run: dart run build_runner build --workspace + + # Verify the use of 'dart format' on each commit. + - name: Verify formatting + run: dart format --output=none --set-exit-if-changed . + + # Ensure the analyzer passes without issues + - name: Analyze project source + run: dart analyze --fatal-infos + + # Ensure the test suite works + - name: Run tests + run: dart test -p vm package/inject_compile/test package/inject_compile_generator/test example/coffee/test example/train/test example/clean_architecture/test \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d24f850 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,14 @@ +name: Publish to pub.dev + +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+*' + +jobs: + publish: + permissions: + id-token: write # Required for authentication using OIDC + uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1 + with: + environment: 'pub.dev' \ No newline at end of file diff --git a/package/inject_compile_generator/lib/src/models/injected_type.dart b/package/inject_compile_generator/lib/src/models/injected_type.dart index cddc5d8..c7c33cc 100644 --- a/package/inject_compile_generator/lib/src/models/injected_type.dart +++ b/package/inject_compile_generator/lib/src/models/injected_type.dart @@ -1,12 +1,8 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:meta/meta.dart'; import 'lookup_key.dart'; -part 'injected_type.g.dart'; - /// A type that is being injected, with metadata about how it is being injected. @immutable -@JsonSerializable() class InjectedType { /// The type the user is trying to inject. final LookupKey lookupKey; @@ -16,10 +12,15 @@ class InjectedType { const InjectedType({required this.lookupKey, this.isProvider = false}); - factory InjectedType.fromJson(Map json) => - _$InjectedTypeFromJson(json); + factory InjectedType.fromJson(Map json) => InjectedType( + lookupKey: LookupKey.fromJson(json['lookupKey'] as Map), + isProvider: json['isProvider'] as bool? ?? false, + ); - Map toJson() => _$InjectedTypeToJson(this); + Map toJson() => { + 'lookupKey': lookupKey.toJson(), + 'isProvider': isProvider, + }; @override bool operator ==(Object other) => diff --git a/package/inject_compile_generator/lib/src/models/lookup_key.dart b/package/inject_compile_generator/lib/src/models/lookup_key.dart index 6fd3d4f..da1f23b 100644 --- a/package/inject_compile_generator/lib/src/models/lookup_key.dart +++ b/package/inject_compile_generator/lib/src/models/lookup_key.dart @@ -1,12 +1,8 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:meta/meta.dart'; import 'symbol_path.dart'; -part 'lookup_key.g.dart'; - /// A representation of a key in the dependency injection graph. @immutable -@JsonSerializable() class LookupKey { /// The [SymbolPath] of the root type. final SymbolPath root; @@ -16,10 +12,17 @@ class LookupKey { const LookupKey({required this.root, this.qualifier}); - factory LookupKey.fromJson(Map json) => - _$LookupKeyFromJson(json); - - Map toJson() => _$LookupKeyToJson(this); + factory LookupKey.fromJson(Map json) => LookupKey( + root: SymbolPath.fromJson(json['root'] as Map), + qualifier: json['qualifier'] == null + ? null + : SymbolPath.fromJson(json['qualifier'] as Map), + ); + + Map toJson() => { + 'root': root.toJson(), + if (qualifier != null) 'qualifier': qualifier!.toJson(), + }; /// A human-readable string representation of this key. String toPrettyString() { diff --git a/package/inject_compile_generator/lib/src/models/summary.dart b/package/inject_compile_generator/lib/src/models/summary.dart index f8ef966..bba7853 100644 --- a/package/inject_compile_generator/lib/src/models/summary.dart +++ b/package/inject_compile_generator/lib/src/models/summary.dart @@ -1,10 +1,7 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:meta/meta.dart'; import 'injected_type.dart'; import 'symbol_path.dart'; -part 'summary.g.dart'; - /// The kind of provider. enum ProviderKind { /// A method annotated with `@provide` in a module. @@ -19,7 +16,6 @@ enum ProviderKind { /// Metadata for a provider (method or constructor). @immutable -@JsonSerializable() class ProviderSummary { /// The name of the method or constructor. final String name; @@ -49,14 +45,33 @@ class ProviderSummary { }); factory ProviderSummary.fromJson(Map json) => - _$ProviderSummaryFromJson(json); - - Map toJson() => _$ProviderSummaryToJson(this); + ProviderSummary( + name: json['name'] as String, + resultType: InjectedType.fromJson( + json['resultType'] as Map, + ), + kind: ProviderKind.values.byName(json['kind'] as String), + isSingleton: json['isSingleton'] as bool? ?? false, + isAsynchronous: json['isAsynchronous'] as bool? ?? false, + dependencies: + (json['dependencies'] as List?) + ?.map((e) => InjectedType.fromJson(e as Map)) + .toList() ?? + const [], + ); + + Map toJson() => { + 'name': name, + 'resultType': resultType.toJson(), + 'kind': kind.name, + 'isSingleton': isSingleton, + 'isAsynchronous': isAsynchronous, + 'dependencies': dependencies.map((e) => e.toJson()).toList(), + }; } /// Metadata for a module class. @immutable -@JsonSerializable() class ModuleSummary { /// The class that defines the module. final SymbolPath clazz; @@ -66,15 +81,21 @@ class ModuleSummary { const ModuleSummary({required this.clazz, required this.providers}); - factory ModuleSummary.fromJson(Map json) => - _$ModuleSummaryFromJson(json); - - Map toJson() => _$ModuleSummaryToJson(this); + factory ModuleSummary.fromJson(Map json) => ModuleSummary( + clazz: SymbolPath.fromJson(json['clazz'] as Map), + providers: (json['providers'] as List) + .map((e) => ProviderSummary.fromJson(e as Map)) + .toList(), + ); + + Map toJson() => { + 'clazz': clazz.toJson(), + 'providers': providers.map((e) => e.toJson()).toList(), + }; } /// Metadata for an injector class. @immutable -@JsonSerializable() class InjectorSummary { /// The abstract class that defines the injector. final SymbolPath clazz; @@ -92,14 +113,25 @@ class InjectorSummary { }); factory InjectorSummary.fromJson(Map json) => - _$InjectorSummaryFromJson(json); - - Map toJson() => _$InjectorSummaryToJson(this); + InjectorSummary( + clazz: SymbolPath.fromJson(json['clazz'] as Map), + modules: (json['modules'] as List) + .map((e) => SymbolPath.fromJson(e as Map)) + .toList(), + providers: (json['providers'] as List) + .map((e) => ProviderSummary.fromJson(e as Map)) + .toList(), + ); + + Map toJson() => { + 'clazz': clazz.toJson(), + 'modules': modules.map((e) => e.toJson()).toList(), + 'providers': providers.map((e) => e.toJson()).toList(), + }; } /// Metadata for a class that can be injected (e.g. annotated with `@provide` on constructor). @immutable -@JsonSerializable() class InjectableSummary { /// The class that is injectable. final SymbolPath clazz; @@ -110,14 +142,21 @@ class InjectableSummary { const InjectableSummary({required this.clazz, required this.constructor}); factory InjectableSummary.fromJson(Map json) => - _$InjectableSummaryFromJson(json); - - Map toJson() => _$InjectableSummaryToJson(this); + InjectableSummary( + clazz: SymbolPath.fromJson(json['clazz'] as Map), + constructor: ProviderSummary.fromJson( + json['constructor'] as Map, + ), + ); + + Map toJson() => { + 'clazz': clazz.toJson(), + 'constructor': constructor.toJson(), + }; } /// The top-level summary for a Dart library. @immutable -@JsonSerializable() class LibrarySummary { /// The URI of the library (asset scheme). final String assetUri; @@ -138,8 +177,29 @@ class LibrarySummary { this.injectables = const [], }); - factory LibrarySummary.fromJson(Map json) => - _$LibrarySummaryFromJson(json); - - Map toJson() => _$LibrarySummaryToJson(this); + factory LibrarySummary.fromJson(Map json) => LibrarySummary( + assetUri: json['assetUri'] as String, + modules: + (json['modules'] as List?) + ?.map((e) => ModuleSummary.fromJson(e as Map)) + .toList() ?? + const [], + injectors: + (json['injectors'] as List?) + ?.map((e) => InjectorSummary.fromJson(e as Map)) + .toList() ?? + const [], + injectables: + (json['injectables'] as List?) + ?.map((e) => InjectableSummary.fromJson(e as Map)) + .toList() ?? + const [], + ); + + Map toJson() => { + 'assetUri': assetUri, + 'modules': modules.map((e) => e.toJson()).toList(), + 'injectors': injectors.map((e) => e.toJson()).toList(), + 'injectables': injectables.map((e) => e.toJson()).toList(), + }; } diff --git a/package/inject_compile_generator/lib/src/models/symbol_path.dart b/package/inject_compile_generator/lib/src/models/symbol_path.dart index 6bb01ef..8443cc0 100644 --- a/package/inject_compile_generator/lib/src/models/symbol_path.dart +++ b/package/inject_compile_generator/lib/src/models/symbol_path.dart @@ -1,11 +1,7 @@ -import 'package:json_annotation/json_annotation.dart'; import 'package:meta/meta.dart'; -part 'symbol_path.g.dart'; - /// The absolute canonical location of a symbol within Dart. @immutable -@JsonSerializable() class SymbolPath { /// The name of the package containing the Dart source code. /// @@ -47,10 +43,24 @@ class SymbolPath { : package = null, path = null; - factory SymbolPath.fromJson(Map json) => - _$SymbolPathFromJson(json); + factory SymbolPath.fromJson(Map json) => SymbolPath( + package: json['package'] as String?, + path: json['path'] as String?, + symbol: json['symbol'] as String, + typeArguments: + (json['typeArguments'] as List?) + ?.map((e) => SymbolPath.fromJson(e as Map)) + .toList() ?? + const [], + ); - Map toJson() => _$SymbolPathToJson(this); + Map toJson() => { + if (package != null) 'package': package, + if (path != null) 'path': path, + 'symbol': symbol, + if (typeArguments.isNotEmpty) + 'typeArguments': typeArguments.map((e) => e.toJson()).toList(), + }; /// Whether the [path] points within the Dart SDK, not a pub package. bool get isDartSdk => package == 'dart'; diff --git a/package/inject_compile_generator/pubspec.yaml b/package/inject_compile_generator/pubspec.yaml index 1a06c2f..212823c 100644 --- a/package/inject_compile_generator/pubspec.yaml +++ b/package/inject_compile_generator/pubspec.yaml @@ -16,7 +16,6 @@ dependencies: build: ^4.0.6 code_builder: ^4.11.0 collection: ^1.19.1 - json_annotation: ^4.12.0 logging: ^1.3.0 meta: ^1.18.0 path: ^1.9.0 @@ -26,6 +25,5 @@ dev_dependencies: build_runner: ^2.15.0 build_test: ^3.5.15 inject_compile: ^0.9.0 - json_serializable: ^6.14.0 lints: ^6.0.0 test: ^1.31.0