0

I have a bunch of cells and a file that registers all of them at once, this works fine but i have to maintain this and remember to add the new entries every time, so i'm trying to create this file using code generation, i have my cells annotated with @cell and iterating over them with:

class CellRegisterGenerator extends GeneratorForAnnotation<CellAnnotation> {
  @override
  String generateForAnnotatedElement(
    Element element,
    ConstantReader annotation,
    BuildStep buildStep,
  ) {
    final visitor = ModelVisitor();
    element.visitChildren(visitor);

    final clazz = visitor.className;
    final name = clazz.replaceAll("Cell", "");
    final cellName = StringUtils.camelCaseToLowerUnderscore(name);
    final builder = "${clazz[0].toLowerCase()}${clazz.substring(1)}Builder";

    return '..registerCell("$cellName", builder: $builder)\n';
  }
}
class ModelVisitor extends SimpleElementVisitor<void> {
  late String className;
  final fields = <String, dynamic>{};

  @override
  void visitConstructorElement(ConstructorElement element) {
    final elementReturnType = element.type.returnType.toString();
    className = elementReturnType.replaceFirst('*', '');
  }

  @override
  void visitFieldElement(FieldElement element) {
    final elementType = element.type.toString();
    fields[element.name] = elementType.replaceFirst('*', '');
  }
}

And a builder to generate the final file:

Builder generateCellRegister(BuilderOptions options) =>
    SharedPartBuilder([CellRegisterGenerator()], 'cell');

Builder cellBuilder(BuilderOptions options) {
  return CellBuilder(options);
}

const _partFiles = '.g.part';
const partIdRegExpLiteral = r'[A-Za-z_\d-]+';

class CellBuilder implements Builder {
  CellBuilder(this.builderOptions);

  final BuilderOptions builderOptions;

  final _generatedFileName = 'lib/support/board_cell_builder_config.g.dart';

  @override
  Map<String, List<String>> get buildExtensions {
    return {
      r'$package$': [_generatedFileName],
      //r'.dart': [_generatedFileName],
      //r'.dart': [ '.g.dart' ],
    };
  }

  @override
  FutureOr<void> build(BuildStep buildStep) async {
    final outputId = AssetId(
      buildStep.inputId.package,
      _generatedFileName,
    );

    final code = """
// GENERATED CODE - DO NOT MODIFY BY HAND
// GENERATED CODE - DO NOT MODIFY BY HAND
// GENERATED CODE - DO NOT MODIFY BY HAND
// GENERATED CODE - DO NOT MODIFY BY HAND

part of "cell_builder_config.dart";
class \$CellBuilderConfig {
  void setup() {
    final cells = CellBuilder.instance;
    cells
      
        Add code generated from CellRegisterGenerator here

    ; 
  }
}  
""";

    final formattedCode = DartFormatter().format(code);
    await buildStep.writeAsString(outputId, formattedCode);
  }
}

build.yaml

builders:
  cell_builder:
    import: "package:<app_name>/generators/cell_builder.dart"
    builder_factories: [ "cellBuilder" ]
    build_extensions: { ".dart": [ ".g.dart" ] }
    auto_apply: root_package
    build_to: source
    applies_builders: [ "<app_name>:cell_register" ]

  cell_register:
    import: "package:<app_name>/generators/cell_builder.dart"
    builder_factories: [ "generateCellRegister" ]
    build_extensions: { ".dart": [ ".g.part" ] }
    auto_apply: dependents
    build_to: cache
    runs_before: [ "<app_name>:cell_builder" ]

But i don't know how to connect them, i've read that i could generate the code from CellRegisterGenerator to cache and read it from the CellBuilder, but i can't find how...

I've tryed to tweak things on the build.yaml (build to source/cache), read the freezed, build_runner and src_gen to see how they work in search for information on how do this all work and or Streams to yield the results and write them to the builder...

It may very well be that the code doesn't make sense to what i'm trying to achieve, i'm trying to piece together every bit of information i find, if there's anything wrong, please do point it out

Dani
  • 3
  • 1
  • 3

0 Answers0