dart-lang / dart-lang/source_gen

Guidance on how to create our own Builder

Open
#745 1 comment 2 reactions 0 assignees View on GitHub
Dominant language
Dart
Stars
494
Forks
115
Avg merge
12h 13m
Merged PRs (30d)
3

Description

Hi, I am writing this seeking for help, since it's quite complicated to find resources on the best way to create Builders 🙂

For our project, we created our own Builder for a specific task. From an input file containing annotated elements, we'd like to obtain a `.rpc.dart` generated file. Then, we want to apply the [retrofit builder](https://pub.dev/packages/retrofit) on this generated file, to obtain the output, a generated file with `.g.dart` extension.

For this, we created `rpc_generator` using `source_gen`. The `build.yaml` file looks like this:
```
builders:
rpc_generator:
import: "package:rpc_generator/rpc_generator.dart"
builder_factories: ["rpcBuilder"]
build_extensions: { ".dart": [".rpc.dart"] }
auto_apply: dependents
build_to: source
runs_before: ["retrofit_generator"]
applies_builders: ["retrofit_generator"]
```

`rpc_generator.dart` contains the following:
`Builder rpcBuilder(BuilderOptions options) => generatorFactoryBuilder(options);`

And finally, the builder and generator themselves:
```
Builder generatorFactoryBuilder(BuilderOptions _) {
return PartBuilder(
[const RpcGenerator()],
'.rpc.dart',
header: '''
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
''',
);
}

class RpcGenerator extends Generator {
const RpcGenerator();

@override
Future generate(LibraryReader library, BuildStep buildStep) async {
...
}
}
```

In local, we have this `build.yaml` file to call our `Builder` on our files:
```
global_options:
freezed:
runs_before:
- json_serializable
json_serializable:
runs_before:
- retrofit_generator
- rpc_generator

targets:
$default:
builders:
...
rpc_generator:rpcBuilder:
generate_for:
- lib/api/rpc/*.api.dart;
- lib/api/*.api.dart
```

My questions are the following:

1. We used a `PartBuilder` because we have to keep both outputs from our `Builder` and `retrofit` builder. But is it possible to do better for this task? Like have a `SharedPartBuilder` that first generate a `.g.dart` containing our generated code, then run `retrofit` builder on this generated code and combine both outputs in a single `.g.dart` file ?
2. When launching `dart run build_runner build --delete-conflicting-outputs` in local, a warning appears: ``Warning: Configuring `rpc_generator:rpcBuilder` in target `data:data` but this is not a known Builder``. Yet, our files are generating correctly. However, when our CI launches the same command through GitHub Actions, the files are not generated. I do not understand why this warning is triggered and why the `build_runner` behavior changes from local to remote ?
3. In our local `build.yaml` file, we HAVE to call the builder like this: `rpc_generator:rpcBuilder:`, otherwise the files are not generated if we only put `rpc_generator:`. From what I understood, if the builder has the same name as its package, we should be able to call `rpc_generator:` directly without having to specify the builder factory. Do you have an idea why this is happening?

Thanks in advance for your help 🙂 I can provide more details if needed.

Contributor guide

Open the contributing guide

Research direction

Start with the package build.yaml, rpc_generator.dart, generatorFactoryBuilder, and the documented PartBuilder and SharedPartBuilder APIs. Reproduce the build_runner command locally, then compare builder registration and configuration with the CI setup. Done means providing clear guidance for chaining the generators, explaining the unknown-builder warning and factory naming, and identifying why CI differs.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart
Domain
build-system, tooling
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.