Skip to content

Commit

Permalink
feat(#77): format files
Browse files Browse the repository at this point in the history
  • Loading branch information
francescovallone committed Sep 10, 2024
1 parent e881951 commit 557711b
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 269 deletions.
46 changes: 18 additions & 28 deletions packages/serinus/bin/serinus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ class TestProviderTwo extends Provider
}
}

class TestProviderThree extends Provider with OnApplicationInit{

class TestProviderThree extends Provider with OnApplicationInit {
final TestProvider testProvider;

TestProviderThree(this.testProvider);
Expand All @@ -50,7 +49,6 @@ class TestProviderThree extends Provider with OnApplicationInit{
Future<void> onApplicationInit() async {
print('Provider three initialized');
}

}

class TestProviderFour extends Provider with OnApplicationInit {
Expand All @@ -69,44 +67,36 @@ class TestProviderFour extends Provider with OnApplicationInit {
class CircularDependencyModule extends Module {
CircularDependencyModule()
: super(imports: [
AnotherModule()
], controllers: [], providers: [
Provider.deferred(
(TestProvider tp) => TestProviderThree(tp),
inject: [TestProvider],
type: TestProviderThree
),
], exports: [TestProviderThree], middlewares: []);
AnotherModule()
], controllers: [], providers: [
Provider.deferred((TestProvider tp) => TestProviderThree(tp),
inject: [TestProvider], type: TestProviderThree),
], exports: [
TestProviderThree
], middlewares: []);
}

class AnotherModule extends Module {
AnotherModule()
: super(imports: [], controllers: [], providers: [
Provider.deferred(
(TestProviderTwo tp, TestProviderThree t) => TestProviderFour(t, tp),
inject: [TestProviderTwo, TestProviderThree],
type: TestProviderFour
),
Provider.deferred(
(TestProviderTwo tp, TestProviderThree t) =>
TestProviderFour(t, tp),
inject: [TestProviderTwo, TestProviderThree],
type: TestProviderFour),
], middlewares: []);
}


class AppModule extends Module {
AppModule()
: super(imports: [
AnotherModule(),

AnotherModule(),
CircularDependencyModule()
], controllers: [
], providers: [
], controllers: [], providers: [
TestProvider(isGlobal: true),
Provider.deferred(
(TestProviderThree tp) => TestProviderTwo(tp),
inject: [TestProviderThree],
type: TestProviderTwo
),
], middlewares: [
]);
Provider.deferred((TestProviderThree tp) => TestProviderTwo(tp),
inject: [TestProviderThree], type: TestProviderTwo),
], middlewares: []);
}

void main(List<String> arguments) async {
Expand Down
92 changes: 56 additions & 36 deletions packages/serinus/lib/src/containers/module_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ final class ModulesContainer {
final newInjectables = ModuleInjectables(
middlewares: {...module.middlewares},
);
_moduleInjectables[token] = moduleInjectables?.concatTo(newInjectables) ?? newInjectables;
_moduleInjectables[token] =
moduleInjectables?.concatTo(newInjectables) ?? newInjectables;
}
final split = initializedModule.providers.splitBy<DeferredProvider>();
for (final provider in split.notOfType) {
Expand Down Expand Up @@ -174,19 +175,23 @@ final class ModulesContainer {
));
continue;
}
final initializedProviders = (_moduleInjectables[token]?.providers.where(
(e) => provider.inject.contains(e.runtimeType)) ?? []
).toList();
if(initializedProviders.isEmpty && provider.inject.isNotEmpty) {
final initializedProviders = (_moduleInjectables[token]
?.providers
.where((e) => provider.inject.contains(e.runtimeType)) ??
[])
.toList();
if (initializedProviders.isEmpty && provider.inject.isNotEmpty) {
throw InitializationError(
'[${module.runtimeType}] Cannot resolve dependencies for a DeferredProvider! Do the following to fix this error: \n'
'1. Make sure all the dependencies are correctly imported in the module. \n'
'2. Make sure the dependencies are correctly exported by their module. \n'
'If the error persists, please check the logs for more information and open an issue on the repository.',
);
}
Map<Type, Provider> dependenciesMap = generateDependenciesMap(initializedProviders);
final result = await Function.apply(provider.init, provider.inject.map((e) => dependenciesMap[e]).toList());
Map<Type, Provider> dependenciesMap =
generateDependenciesMap(initializedProviders);
final result = await Function.apply(provider.init,
provider.inject.map((e) => dependenciesMap[e]).toList());
checkResultType(provider, result, module);
await initIfUnregistered(result);
parentModule.providers.add(result);
Expand All @@ -195,51 +200,63 @@ final class ModulesContainer {
} else {
_providers[token]?.add(result);
}
_moduleInjectables[token]?.replaceDeferredProvider(provider.hashCode, result);
_deferredProviders[token] = _deferredProviders[token]?.where((e) => e.hashCode != provider.hashCode) ?? [];
_moduleInjectables[token]
?.replaceDeferredProvider(provider.hashCode, result);
_deferredProviders[token] = _deferredProviders[token]
?.where((e) => e.hashCode != provider.hashCode) ??
[];
injectProvidersInSubModule(module);
}
}
}

/// Checks the result type of the deferred provider
void checkResultType(DeferredProvider provider, dynamic result, Module module) {
if(result is DeferredProvider) {
throw InitializationError('[${module.runtimeType}] A DeferredProvider cannot return another DeferredProvider');
void checkResultType(
DeferredProvider provider, dynamic result, Module module) {
if (result is DeferredProvider) {
throw InitializationError(
'[${module.runtimeType}] A DeferredProvider cannot return another DeferredProvider');
}
if(result is! Provider) {
throw InitializationError('[${module.runtimeType}] ${result.runtimeType} is not a Provider');
if (result is! Provider) {
throw InitializationError(
'[${module.runtimeType}] ${result.runtimeType} is not a Provider');
}
if(result.runtimeType != provider.type) {
throw InitializationError('[${module.runtimeType}] ${result.runtimeType} has a different type than the expected type ${provider.type}');
if (result.runtimeType != provider.type) {
throw InitializationError(
'[${module.runtimeType}] ${result.runtimeType} has a different type than the expected type ${provider.type}');
}
}

/// Recursively resolves the dependencies of the deferred providers
Future<void> resolveProvidersDependencies() async {
if(_providerDependencies.every((e) => e.isInitialized)) {
if (_providerDependencies.every((e) => e.isInitialized)) {
return;
}
for (final entry in _providerDependencies) {
if (entry.isInitialized) {
continue;
}
final _ProviderDependencies(: provider, : module, : dependencies) = entry;
final _ProviderDependencies(:provider, :module, :dependencies) = entry;
final token = moduleToken(module);
final initializedProviders = _moduleInjectables[token]?.providers.where(
(e) => dependencies.contains(e.runtimeType),
).toList();
final initializedProviders = _moduleInjectables[token]
?.providers
.where(
(e) => dependencies.contains(e.runtimeType),
)
.toList();
checkForCircularDependencies(provider, module, dependencies.toList());
if(initializedProviders?.isEmpty ?? true && dependencies.isNotEmpty) {
if (initializedProviders?.isEmpty ?? true && dependencies.isNotEmpty) {
throw InitializationError(
'[${module.runtimeType}] Cannot resolve dependencies for a DeferredProvider! Do the following to fix this error: \n'
'1. Make sure all the dependencies are correctly imported in the module. \n'
'2. Make sure the dependencies are correctly exported by their module. \n'
'If the error persists, please check the logs for more information and open an issue on the repository.',
);
}
Map<Type, Provider> dependenciesMap = generateDependenciesMap(initializedProviders);
final result = await Function.apply(provider.init, provider.inject.map((e) => dependenciesMap[e]).toList());
Map<Type, Provider> dependenciesMap =
generateDependenciesMap(initializedProviders);
final result = await Function.apply(provider.init,
provider.inject.map((e) => dependenciesMap[e]).toList());
checkResultType(provider, result, module);
module.providers.add(result);
await initIfUnregistered(result);
Expand All @@ -248,7 +265,8 @@ final class ModulesContainer {
} else {
_providers[token]?.add(result);
}
_moduleInjectables[token]?.replaceDeferredProvider(provider.hashCode, result);
_moduleInjectables[token]
?.replaceDeferredProvider(provider.hashCode, result);
entry.isInitialized = true;
await resolveProvidersDependencies();
}
Expand Down Expand Up @@ -401,22 +419,27 @@ final class ModulesContainer {
_modules.values.expand((element) => element.providers).toList();
return providers.whereType<T>().toList();
}

/// Checks for circular dependencies
void checkForCircularDependencies(DeferredProvider provider, Module parentModule, List<Type> dependencies) {
void checkForCircularDependencies(
DeferredProvider provider, Module parentModule, List<Type> dependencies) {
final branchProviders = [
...parentModule.imports.map((e) => e.providers).flatten(),
...parentModule.providers,
];
for (final p in branchProviders) {
if (p is DeferredProvider && dependencies.contains(p.type) && p.inject.contains(provider.type)) {
throw InitializationError('[${parentModule.runtimeType}] Circular dependency found in ${provider.type}');
if (p is DeferredProvider &&
dependencies.contains(p.type) &&
p.inject.contains(provider.type)) {
throw InitializationError(
'[${parentModule.runtimeType}] Circular dependency found in ${provider.type}');
}
}
}

/// Generates the dependencies map
Map<Type, Provider> generateDependenciesMap(List<Provider>? initializedProviders) {
Map<Type, Provider> generateDependenciesMap(
List<Provider>? initializedProviders) {
Map<Type, Provider> dependenciesMap = {};
for (final provider in initializedProviders!) {
dependenciesMap[provider.runtimeType] = provider;
Expand Down Expand Up @@ -491,14 +514,12 @@ class ModuleInjectables {
/// Remove a DeferredProvider from the providers based on its hashcode and replace it with a Provider
void replaceDeferredProvider(int hashcode, Provider provider) {
providers
..removeWhere((element) => element.hashCode == hashcode)
..add(provider);
..removeWhere((element) => element.hashCode == hashcode)
..add(provider);
}

}

class _ProviderDependencies {

final DeferredProvider provider;
final Module module;
final Iterable<Type> dependencies;
Expand All @@ -509,5 +530,4 @@ class _ProviderDependencies {
required this.module,
required this.dependencies,
});

}
1 change: 0 additions & 1 deletion packages/serinus/lib/src/core/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,4 @@ abstract class Module {
Future<Module> registerAsync(ApplicationConfig config) async {
return this;
}

}
16 changes: 4 additions & 12 deletions packages/serinus/lib/src/core/provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ abstract class Provider {
///
/// The [init] function is called when the provider is initialized.
/// The [inject] property contains the types of other [Provider]s that will be injected in the provider.
factory Provider.deferred(
Function init, {
required List<Type> inject,
required Type type
}) =>
factory Provider.deferred(Function init,
{required List<Type> inject, required Type type}) =>
DeferredProvider(init, inject: inject, type: type);
}

Expand All @@ -26,17 +23,12 @@ class DeferredProvider extends Provider {
/// The [init] function is called when the provider is initialized.
final Function init;

/// The [type] property contains the type of the provider that will be initialized.
/// The [type] property contains the type of the provider that will be initialized.
final Type type;

/// The [inject] property contains the types of other [Provider]s that will be injected in the provider.
final List<Type> inject;

/// The [DeferredProvider] constructor is used to create a new instance of the [DeferredProvider] class.
DeferredProvider(
this.init, {
required this.inject,
required this.type
}
);
DeferredProvider(this.init, {required this.inject, required this.type});
}
24 changes: 9 additions & 15 deletions packages/serinus/test/containers/modules_container_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,18 @@ import 'package:test/test.dart';
import '../mocks/injectables_mock.dart';
import '../mocks/module_mock.dart';


class _MockAdapter extends Mock implements Adapter {}

void main() {
group('$ModulesContainer', () {
test(
'registerModules should register a module in the container and store it in the modules list',
() async {
final container = ModulesContainer(
ApplicationConfig(
final container = ModulesContainer(ApplicationConfig(
host: 'localhost',
port: 3000,
serverAdapter: _MockAdapter(),
poweredByHeader: 'Serinus'
)
);
poweredByHeader: 'Serinus'));
final module = SimpleModule();
await container.registerModules(module, module.runtimeType);
expect(container.modules.length, 1);
Expand All @@ -29,14 +25,11 @@ void main() {
test(
'registerModules should throw an $InitializationError when a module is registered multiple times',
() async {
final container = ModulesContainer(
ApplicationConfig(
final container = ModulesContainer(ApplicationConfig(
host: 'localhost',
port: 3000,
serverAdapter: _MockAdapter(),
poweredByHeader: 'Serinus'
)
);
poweredByHeader: 'Serinus'));
final module = SimpleModule();
await container.registerModules(module, module.runtimeType);
expect(() => container.registerModules(module, module.runtimeType),
Expand Down Expand Up @@ -119,8 +112,7 @@ void main() {
throwsA(isA<ArgumentError>()));
});

test(
'''
test('''
registerModule should register a module with imports and injectables,
then the ModulesContainer should create two ModuleInjectables which for the main module contains all its own injectables and the providers from the imported module,
''', () async {
Expand All @@ -146,12 +138,14 @@ void main() {
container.getModuleInjectablesByToken(t.toString());
expect(injectables.middlewares.length, 1);
expect(subInjectables.providers.length, 2);
expect(injectables.providers.where((e) => e.runtimeType == subInjectables.providers.last.runtimeType), isNotEmpty);
expect(
injectables.providers.where((e) =>
e.runtimeType == subInjectables.providers.last.runtimeType),
isNotEmpty);
final t2 = ImportableModuleWithNonExportedProvider;
final subInjectablesTwo =
container.getModuleInjectablesByToken(t2.toString());
expect(subInjectablesTwo.providers.length, 3);
});

});
}
3 changes: 1 addition & 2 deletions packages/serinus/test/core/contexts_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ class TestProvider extends Provider {
TestProvider();
}

void main() async {
}
void main() async {}
Loading

0 comments on commit 557711b

Please sign in to comment.