generate method

  1. @override
FutureOr<String?> generate(
  1. LibraryReader library,
  2. BuildStep buildStep
)

Generates Dart code for an input Dart library.

May create additional outputs through the buildStep, but the 'primary' output is Dart code returned through the Future. If there is nothing to generate for this library may return null, or a Future that resolves to null or the empty string.

Implementation

@override
FutureOr<String?> generate(LibraryReader library, BuildStep buildStep) async {
  /// String Variables
  /// These variables will keep strings of generated code separately
  /// [statisticsCodeBody] the package will generate some statistics about received code which will put at the top of generated code
  /// [importsCodeBody] this is the [import] section, all the demanded imports will gather, save and finally generate here
  /// [pagesCodeBody] we have a section for store and generate pages which we should represent to [GetX] separately
  /// [initialPageString] in the pages section we should hold a initial page to represent to [GetX]
  /// [unknownPageString] therefore, we have a unknown route to represent
  /// [controllersCodeBody] controllers are controllers of the pages
  /// [componentsCodeBody] components are Components of the Project
  /// [servicesCodeBody] services are Services of the Project
  /// [repositoriesCodeBody] repositories could include all the repositories in the app, everything that you can name as repository
  /// all these 3 fields are known as Controllers in the [GetX] but they can have separate meanings or concepts
  /// so we will separate them as meanings, but they will add to the dependencies part which is the next
  /// and they have a similar behavior as [GetX] perspective
  /// [dependenciesCodeBody] this part provides all 3 dependency functions and merge them into a function to represent
  /// [bindingsCodeBody]
  ///
  /// then we can have them in different parts, at first step it will so much easier to debug and find every problem
  /// which occurred and generated by every part of the code
  /// at the end, all of them will merge in a unified string for pass to the generating the file
  /// the only variable that could assume different is [mainCodeBody] which will keep the final merged code

  String statisticsCodeBody = Strings.empty;
  String importsCodeBody = Strings.empty;
  String pagesCodeBody = Strings.empty;
  String initialPageString = Strings.empty;
  String unknownPageString = Strings.empty;
  String controllersCodeBody = Strings.empty;
  String componentsCodeBody = Strings.empty;
  String repositoriesCodeBody = Strings.empty;
  String servicesCodeBody = Strings.empty;
  String dependenciesCodeBody = Strings.empty;
  String bindingsCodeBody = Strings.empty;
  String mainCodeBody = Strings.empty;

  /// Generator could generate everywhere and with every file
  /// it will be restricted this way to generate specific file and save resources
  bool canGenerate = library.element.uri.path.contains(ImportDependencies.main.url);
  if (canGenerate) {
    GeneratorLog(title: 'Code Generation Started...');

    /// Imports Generation
    importsCodeBody = importsCodeBody.addImport(ImportDependencies.get.url);
    importsCodeBody = importsCodeBody.addImport(ImportDependencies.main.url);
    for (var import in importsList) {
      if (!import.contains('${ImportDependencies.main.url}')) importsCodeBody = importsCodeBody.addImport(import);
    }

    /// Statistics
    statisticsCodeBody = statisticsCodeBody.addCommentLine('Generated Library Statistics:');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Imports Count: ${importsList.length}');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Pages Count: ${pagesList.length}');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Controllers Count: ${controllersList.length}');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Components Count: ${componentsList.length}');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Repositories Count: ${repositoriesList.length}');
    statisticsCodeBody = statisticsCodeBody.addCommentLineWithSpace('Services Count: ${servicesList.length}');

    /// Bodies Generation
    /// Pages
    String pages = Strings.empty;

    /// Check [Initial] and [Unknown] Routes
    /// [Initial] and [unknown] Pages are mandatory
    bool hasInitial = pagesList.where((element) => element.initialRoute == true).isNotEmpty;
    bool hasUnknown = pagesList.where((element) => element.unknownRoute == true).isNotEmpty;
    if (!hasInitial || !hasUnknown) {
      GeneratorLog.error(title: 'Error Occurred', data: 'Initial and/or Unknown Route has not been Set');
      throw Exception('Error occurred, Pages and Routes can\'t be generated without Initial and Unknown Page');
    }

    /// Page Lines
    for (var page in pagesList) pages = pages.addLine('${_pageDependencyFormat(page)},');

    /// [InitialPage] and [UnknownPage] Page Lines
    initialPageString = 'static String get initialRoute => ${_pageDependencyFormat(pagesList.firstWhere((value) => value.initialRoute == true))}.name;';
    unknownPageString = 'static GetPage get unknownRoute => ${_pageDependencyFormat(pagesList.firstWhere((value) => value.unknownRoute == true))};';

    pagesCodeBody = pagesCodeBody.addClass(
      className: '${AnnotationTypes.page.name.capitalizeFirst}s',
      body: 'static List<GetPage> get ${AnnotationTypes.page.name}s => [$pages\n]; $initialPageString $unknownPageString');

    /// Add Dependencies
    for (var controller in controllersList) controllersCodeBody = controllersCodeBody.addLine(_controllerDependencyFormat(controller));
    for (var component in componentsList) componentsCodeBody = componentsCodeBody.addLine(_controllerDependencyFormat(component));
    for (var repository in repositoriesList) repositoriesCodeBody = repositoriesCodeBody.addLine(_controllerDependencyFormat(repository));
    for (var service in servicesList) servicesCodeBody = servicesCodeBody.addLine(_serviceDependencyFormat(service));

    /// Dependencies CodeBody
    dependenciesCodeBody = dependenciesCodeBody.addDependencyClass(className: AnnotationTypes.controller.name.capitalizeFirst, body: controllersCodeBody);
    dependenciesCodeBody = dependenciesCodeBody.addDependencyClass(className: AnnotationTypes.component.name.capitalizeFirst, body: componentsCodeBody);
    dependenciesCodeBody = dependenciesCodeBody.addDependencyClass(className: AnnotationTypes.repository.name.capitalizeFirst, body: repositoriesCodeBody);
    dependenciesCodeBody = dependenciesCodeBody.addDependencyClass(className: AnnotationTypes.service.name.capitalizeFirst, body: servicesCodeBody);

    /// Dependencies Bindings
    bindingsCodeBody = bindingsCodeBody.addLine(_addBindingLine(annotation: AnnotationTypes.controller));
    bindingsCodeBody = bindingsCodeBody.addLine(_addBindingLine(annotation: AnnotationTypes.component));
    bindingsCodeBody = bindingsCodeBody.addLine(_addBindingLine(annotation: AnnotationTypes.repository));
    bindingsCodeBody = bindingsCodeBody.addLine(_addBindingLine(annotation: AnnotationTypes.service));

    /// CodeBody Generation
    mainCodeBody = mainCodeBody.addLine('library;').addSpaceAfter();
    mainCodeBody = mainCodeBody.addCommentLine(DescriptionGenerator().generate(all: true)).addSpaceAfter();
    mainCodeBody = mainCodeBody.addLine(importsCodeBody).addSpaceAfter();
    mainCodeBody = mainCodeBody.addLine(statisticsCodeBody).addSpaceAfter();
    mainCodeBody = mainCodeBody.addLine(pagesCodeBody).addSpaceAfter();
    mainCodeBody = mainCodeBody.addBindingClass(body: bindingsCodeBody).addSpaceAfter();
    mainCodeBody = mainCodeBody.addLine(dependenciesCodeBody).addSpaceAfter();

    GeneratorLog(
      title:
          '${pagesList.length} Pages,'
          '${controllersList.length} Controllers, '
          '${componentsList.length} Components, '
          '${repositoriesList.length} Repositories, '
          '${servicesList.length} Services '
          'Founded and Added...',
    );
    GeneratorLog(title: 'Code Generation Completed...');
  }

  return mainCodeBody.isNotEmpty && canGenerate ? mainCodeBody : null;
}