Files
cherrypick/cherrypick_generator/lib/src/generated_class.dart

127 lines
4.2 KiB
Dart
Raw Normal View History

2025-05-21 15:50:24 +03:00
//
// Copyright 2021 Sergey Penkovsky (sergey.penkovsky@gmail.com)
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2025-08-08 23:24:05 +03:00
// https://www.apache.org/licenses/LICENSE-2.0
2025-05-21 15:50:24 +03:00
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import 'package:analyzer/dart/element/element.dart';
import 'bind_spec.dart';
2025-05-22 16:05:09 +03:00
/// ---------------------------------------------------------------------------
/// GeneratedClass
2025-05-21 15:50:24 +03:00
///
/// Represents a processed DI module class with all its binding methods analyzed.
/// Stores:
/// - The original class name,
/// - The generated implementation class name (with $ prefix),
/// - The list of all BindSpec for the module methods,
/// - The source file name for reference or directive generation.
2025-05-22 16:05:09 +03:00
///
/// Provides static and instance methods to construct from a ClassElement
/// and generate Dart source code for the resulting DI registration class.
2025-05-22 16:05:09 +03:00
///
/// ## Example usage
/// ```dart
/// final gen = GeneratedClass.fromClassElement(myModuleClassElement);
/// print(gen.generate());
/// /*
/// Produces:
/// final class $MyModule extends MyModule {
/// @override
/// void builder(Scope currentScope) {
/// bind<Service>().toProvide(() => provideService(currentScope.resolve<Dep>()));
/// ...
/// }
/// }
/// */
/// ```
2025-05-22 16:05:09 +03:00
/// ---------------------------------------------------------------------------
2025-05-21 15:50:24 +03:00
class GeneratedClass {
/// Name of the original Dart module class.
2025-05-21 15:50:24 +03:00
final String className;
/// Name of the generated class, e.g. `$MyModule`
2025-05-21 15:50:24 +03:00
final String generatedClassName;
/// Binding specs for all provider/factory methods in the class.
2025-05-21 15:50:24 +03:00
final List<BindSpec> binds;
/// Source filename of the module class (for code references).
final String sourceFile;
2025-05-21 15:50:24 +03:00
GeneratedClass(
this.className,
this.generatedClassName,
this.binds,
this.sourceFile,
2025-05-21 15:50:24 +03:00
);
2025-05-22 16:05:09 +03:00
/// -------------------------------------------------------------------------
/// fromClassElement
///
/// Creates a [GeneratedClass] by analyzing a Dart [ClassElement].
/// Collects all public non-abstract methods, creates a [BindSpec] for each,
/// and infers the generated class name using a `$` prefix.
2025-05-22 16:05:09 +03:00
///
/// ## Example usage
/// ```dart
/// final gen = GeneratedClass.fromClassElement(classElement);
/// print(gen.generatedClassName); // e.g. $AppModule
/// ```
2025-05-21 15:50:24 +03:00
static GeneratedClass fromClassElement(ClassElement element) {
final className = element.displayName;
2025-05-22 16:05:09 +03:00
// Generated class name with '$' prefix (standard for generated Dart code).
2025-05-21 15:50:24 +03:00
final generatedClassName = r'$' + className;
// Get source file name
final sourceFile = element.source.shortName;
2025-05-22 16:05:09 +03:00
// Collect bindings for all non-abstract methods.
2025-05-21 15:50:24 +03:00
final binds = element.methods
.where((m) => !m.isAbstract)
.map(BindSpec.fromMethod)
.toList();
return GeneratedClass(className, generatedClassName, binds, sourceFile);
2025-05-21 15:50:24 +03:00
}
2025-05-22 16:05:09 +03:00
/// -------------------------------------------------------------------------
/// generate
///
/// Generates the Dart source code for the DI registration class.
/// The generated class extends the original module, and the `builder` method
/// registers all bindings (dependencies) into the DI scope.
2025-05-21 15:50:24 +03:00
///
/// ## Example output
/// ```dart
/// final class $UserModule extends UserModule {
/// @override
/// void builder(Scope currentScope) {
/// bind<Service>().toProvide(() => provideService(currentScope.resolve<Dep>()));
/// }
/// }
/// ```
2025-05-21 15:50:24 +03:00
String generate() {
final buffer = StringBuffer()
..writeln('final class $generatedClassName extends $className {')
..writeln(' @override')
..writeln(' void builder(Scope currentScope) {');
2025-05-21 15:50:24 +03:00
2025-05-22 16:05:09 +03:00
// For each binding, generate bind<Type>() code string.
2025-05-21 15:50:24 +03:00
for (final bind in binds) {
buffer.writeln(bind.generateBind(4));
}
buffer
..writeln(' }')
..writeln('}');
2025-05-21 15:50:24 +03:00
return buffer.toString();
}
}