@@ -46,146 +46,138 @@ be configured (as opposed to using part files).
4646
4747## Usage
4848
49- Following the example of [ ` source_gen ` ] [ source_gen ] , it is common practice to separate * builders* and * generators* from the code using those builders.
49+ Following the example of [ ` source_gen ` ] [ source_gen ] , it is common practice to
50+ separate * builders* and * generators* from the code using those builders.
5051
51- In the [ example] provided with this library, the package defining a new builder is called ` researcher_builder ` and the package using this builder is called ` researcher ` . To set up a build system the following steps are required:
52+ In the [ example] provided with this library, the package defining a new
53+ builder is called ` researcher_builder ` and the package using this builder is called ` researcher ` .
54+ To set up a build system the following steps are required:
5255
53561 . Include [ ` merging_builder ` ] [ merging_builder ] , [ ` build ` ] [ build ] as * dependencies* in the file ` pubspec.yaml ` of the package ** defining** the builder. In the [ example] mentioned here, the generator also requires the packages [ ` analyzer ` ] [ analyzer ] and [ ` source_gen ` ] [ source_gen ] .
5457
55582 . In the package ** defining** the custom builder, create a custom generator that extends [ ` MergingGenerator ` ] [ MergingGenerator ] . Users will have to implement the methods ` generateItemForAnnotatedElement ` and ` generateMergedContent ` . In the example shown below ` generateItemForAnnotatedElement ` reads a list of strings while ` generateMergedContent ` merges the data and generates output that is written to [ researchers.dart] .
5659
5760
58- <details > <summary > Show details. </summary >
59-
60- ``` Dart
61-
62- import 'dart:async';
63-
64- import 'package:analyzer/dart/element/element.dart';
65- import 'package:build/build.dart' show BuildStep;
66- import 'package:merging_builder/merging_builder.dart';
67- import 'package:quote_buffer/quote_buffer.dart';
68-
69- import 'package:source_gen/source_gen.dart' show ConstantReader;
70-
71- import '../annotations/add_names.dart';
72-
73-
74- /// Reads a field element of type [List<String] and generates the merged content.
75- class AddNamesGenerator extends MergingGenerator<List<String>, AddNames> {
76- /// Portion of source code included at the top of the generated file.
77- /// Should be specified as header when constructing the merging builder.
78- static String get header {
79- return '/// Added names.';
80- }
81-
82- /// Portion of source code included at the very bottom of the generated file.
83- /// Should be specified as [footer] when constructing the merging builder.
84- static String get footer {
85- return '/// This is the footer.';
86- }
87-
88- @override
89- List<String> generateStreamItemForAnnotatedElement(
90- Element element,
91- ConstantReader annotation,
92- BuildStep buildStep,
93- ) {
94- final result = <String>[];
95- if (element is ClassElement) {
96- final nameObjects =
97- element.getField('names')?.computeConstantValue()?.toListValue();
98- for (final nameObj in nameObjects ?? []) {
99- result.add(nameObj.toStringValue());
100- }
101- return result;
102- }
103- return <String>['Could not read name'];
104- }
105-
106- /// Returns the merged content.
107- @override
108- FutureOr<String> generateMergedContent(Stream<List<String>> stream) async {
109- final b = StringBuffer();
110- var i = 0;
111- final allNames = <List<String>>[];
112- // Iterate over stream:
113- await for (final names in stream) {
114- b.write('final name$i = [');
115- b.writelnAllQ(names, separator2: ',');
116- b.writeln('];');
117- ++i;
118- allNames.add(names);
119- }
120-
121- b.writeln('');
122- b.writeln('final List<List<String>> names = [');
123- for (var names in allNames) {
124- b.writeln(' [');
125- b.writelnAllQ(names, separator2: ',');
126- b.writeln(' ],');
127- }
128- b.writeln('];');
129- return b.toString();
61+ <details > <summary > Show details. </summary >
62+
63+ ``` Dart
64+ import 'dart:async';
65+ import 'package:analyzer/dart/element/element.dart';
66+ import 'package:build/build.dart' show BuildStep;
67+ import 'package:merging_builder/merging_builder.dart';
68+ import 'package:quote_buffer/quote_buffer.dart';
69+ import 'package:source_gen/source_gen.dart' show ConstantReader;
70+ import '../annotations/add_names.dart';
71+ /// Reads a field element of type [List<String] and generates the merged content.
72+ class AddNamesGenerator extends MergingGenerator<List<String>, AddNames> {
73+ /// Portion of source code included at the top of the generated file.
74+ /// Should be specified as header when constructing the merging builder.
75+ static String get header {
76+ return '/// Added names.';
77+ }
78+ /// Portion of source code included at the very bottom of the generated file.
79+ /// Should be specified as [footer] when constructing the merging builder.
80+ static String get footer {
81+ return '/// This is the footer.';
82+ }
83+ @override
84+ List<String> generateStreamItemForAnnotatedElement(
85+ Element element,
86+ ConstantReader annotation,
87+ BuildStep buildStep,
88+ ) {
89+ final result = <String>[];
90+ if (element is ClassElement) {
91+ final nameObjects =
92+ element.getField('names')?.computeConstantValue()?.toListValue();
93+ for (final nameObj in nameObjects ?? []) {
94+ result.add(nameObj.toStringValue());
13095 }
96+ return result;
13197 }
132- ```
98+ return <String>['Could not read name'];
99+ }
100+ /// Returns the merged content.
101+ @override
102+ FutureOr<String> generateMergedContent(Stream<List<String>> stream) async {
103+ final b = StringBuffer();
104+ var i = 0;
105+ final allNames = <List<String>>[];
106+ // Iterate over stream:
107+ await for (final names in stream) {
108+ b.write('final name$i = [');
109+ b.writelnAllQ(names, separator2: ',');
110+ b.writeln('];');
111+ ++i;
112+ allNames.add(names);
113+ }
114+ b.writeln('');
115+ b.writeln('final List<List<String>> names = [');
116+ for (var names in allNames) {
117+ b.writeln(' [');
118+ b.writelnAllQ(names, separator2: ',');
119+ b.writeln(' ],');
120+ }
121+ b.writeln('];');
122+ return b.toString();
123+ }
124+ }
133125
134- </details>
126+ ```
127+ </details >
135128
1361293 . Create an instance of [ ` MergingBuilder ` ] [ MergingBuilder ] . Following the example of [ ` source_gen ` ] [ source_gen ] , builders are typically placed in a file called: ` builder.dart ` located in the ` lib ` folder of the builder package.
137130 * The generator ` AddNamesGenerator ` shown below extends ` MergingGenerator<List<String>, AddNames> ` (see step 2).
138131 * Input sources may be specified using wildcard characters supported by [ ` Glob ` ] [ Glob ] .
139132 * The builder definition shown below honours the * options* ` input_files ` , ` output_file ` , ` header ` , ` footer ` , and ` sort_assets ` that can be set in the file ` build.yaml ` located in the package ` researcher ` (see step 5).
140133
141- ```Dart
142- import 'package:build/build.dart';
143- import 'package:merging_builder/merging_builder.dart';
144-
145- import 'src/generators/add_names_generator.dart';
146- import 'src/generators/assistant_generator.dart';
147-
148- /// Defines a merging builder.
149- /// Honours the options: `input_files`, `output_file`, `header`, `footer`,
150- /// and `sort_assets` that can be set in `build.yaml`.
151- Builder addNamesBuilder(BuilderOptions options) {
152- BuilderOptions defaultOptions = BuilderOptions({
153- 'input_files': 'lib/*.dart',
154- 'output_file': 'lib/output.dart',
155- 'header': AddNamesGenerator.header,
156- 'footer': AddNamesGenerator.footer,
157- 'sort_assets': true,
158- });
159-
160- // Apply user set options.
161- options = defaultOptions.overrideWith(options);
162- return MergingBuilder<List<String>, LibDir>(
163- generator: AddNamesGenerator(),
164- inputFiles: options.config['input_files'],
165- outputFile: options.config['output_file'],
166- header: options.config['header'],
167- footer: options.config['footer'],
168- sortAssets: options.config['sort_assets'],
169- );
170- }
171-
172- /// Defines a standalone builder.
173- Builder assistantBuilder(BuilderOptions options) {
174- BuilderOptions defaultOptions = BuilderOptions({
175- 'input_files': 'lib/*.dart',
176- 'output_files': 'lib/output/assistant_(*).dart',
177- 'header': AssistantGenerator.header,
178- 'footer': AssistantGenerator.footer,
179- 'root': ''
180- });
181- options = defaultOptions.overrideWith(options);
182- return StandaloneBuilder<LibDir>(
183- generator: AssistantGenerator(),
184- inputFiles: options.config['input_files'],
185- outputFiles: options.config['output_files'],
186- root: options.config['root']);
187- }
188- ```
134+ <details > <summary > Show details. </summary >
135+
136+ ``` Dart
137+ import 'package:build/build.dart';
138+ import 'package:merging_builder/merging_builder.dart';
139+ import 'src/generators/add_names_generator.dart';
140+ import 'src/generators/assistant_generator.dart';
141+ /// Defines a merging builder.
142+ /// Honours the options: `input_files`, `output_file`, `header`, `footer`,
143+ /// and `sort_assets` that can be set in `build.yaml`.
144+ Builder addNamesBuilder(BuilderOptions options) {
145+ BuilderOptions defaultOptions = BuilderOptions({
146+ 'input_files': 'lib/*.dart',
147+ 'output_file': 'lib/output.dart',
148+ 'header': AddNamesGenerator.header,
149+ 'footer': AddNamesGenerator.footer,
150+ 'sort_assets': true,
151+ });
152+ // Apply user set options.
153+ options = defaultOptions.overrideWith(options);
154+ return MergingBuilder<List<String>, LibDir>(
155+ generator: AddNamesGenerator(),
156+ inputFiles: options.config['input_files'],
157+ outputFile: options.config['output_file'],
158+ header: options.config['header'],
159+ footer: options.config['footer'],
160+ sortAssets: options.config['sort_assets'],
161+ );
162+ }
163+ /// Defines a standalone builder.
164+ Builder assistantBuilder(BuilderOptions options) {
165+ BuilderOptions defaultOptions = BuilderOptions({
166+ 'input_files': 'lib/*.dart',
167+ 'output_files': 'lib/output/assistant_(*).dart',
168+ 'header': AssistantGenerator.header,
169+ 'footer': AssistantGenerator.footer,
170+ 'root': ''
171+ });
172+ options = defaultOptions.overrideWith(options);
173+ return StandaloneBuilder<LibDir>(
174+ generator: AssistantGenerator(),
175+ inputFiles: options.config['input_files'],
176+ outputFiles: options.config['output_files'],
177+ root: options.config['root']);
178+ }
179+ ```
180+ </details >
189181
1901824 . In the package ** defining** the builder, add the builder configuration for the builder ` add_names_builder ` (see below). The build extensions for
191183[ ` MergingBuilder ` ] [ MergingBuilder ] must be specified using the notation available for ** synthetic input** . For example, ` "$lib$" ` indicates that the
@@ -255,66 +247,8 @@ and [`build_runner`][build_runner] as *dev_dependencies* in the file `pubspec.ya
2552477. Initiate the build process by using the command :
256248 ` ` ` console
257249 # dart run build_runner build --delete-conflicting-outputs --verbose
258- [INFO] Entrypoint:Generating build script...
259- [INFO] Entrypoint:Generating build script completed, took 802ms
260-
261- [INFO] BuildDefinition:Initializing inputs
262- [INFO] BuildDefinition:Reading cached asset graph...
263- [INFO] BuildDefinition:Reading cached asset graph completed, took 99ms
264-
265- [INFO] BuildDefinition:Checking for updates since last build...
266- [INFO] BuildDefinition:Checking for updates since last build completed, took 772ms
267-
268- [INFO] Build:Running build...
269- [FINE] researcher_builder:add_names_builder on lib/$lib$:Running AddNamesGenerator on: lib/input/researcher_b.dart.
270- [FINE] researcher_builder:add_names_builder on lib/$lib$:Running AddNamesGenerator on: lib/input/researcher_a.dart.
271- [FINE] researcher_builder:assistant_builder on lib/$lib$:Running AssistantGenerator on: lib/input/researcher_b.dart.
272- [FINE] researcher_builder:assistant_builder on lib/$lib$:Running AssistantGenerator on: lib/input/researcher_a.dart.
273- [INFO] Build:Running build completed, took 886ms
274-
275- [INFO] Build:Caching finalized dependency graph...
276- [INFO] Build:Caching finalized dependency graph completed, took 70ms
277-
278- [INFO] Build:Succeeded after 973ms with 3 outputs (2 actions)
279250 ` ` `
280251
281- To view the content of the generated files please click below:
282- <details > <summary > lib/output/assistant_researcher_a.dart </summary >
283-
284- ``` Dart
285- // GENERATED CODE. DO NOT MODIFY. Generated by AssistantGenerator.
286- final String assistants = 'Thomas, Mayor';
287- ```
288-
289- </details >
290-
291- <details > <summary > lib/output/assistant_researcher_b.dart </summary >
292-
293- ``` Dart
294- // GENERATED CODE. DO NOT MODIFY. Generated by AssistantGenerator.
295- final String assistants = 'Philip, Martens';
296- ```
297-
298- </details >
299- <details > <summary > lib/output/researchers.dart </summary >
300-
301- ``` Dart
302- // GENERATED CODE. DO NOT MODIFY. Generated by AddNamesGenerator.
303-
304- // Header specified in build.yaml.
305- final name0 = ['Philip', 'Martens'];
306- final name1 = ['Thomas', 'Mayor'];
307-
308- final List<List<String>> names = [
309- ['Philip', 'Martens'],
310- ['Thomas', 'Mayor'],
311- ];
312-
313- // Footer specified in build.yaml.
314- ```
315-
316- </details >
317-
318252# # Implementation Details
319253
320254The classes [`MergingBuilder<T, S extends SyntheticInput>`][class-merging-builder]
0 commit comments