Skip to content

Commit 5322e09

Browse files
committed
Amended docs.
1 parent ecb3b88 commit 5322e09

File tree

5 files changed

+357
-497
lines changed

5 files changed

+357
-497
lines changed

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11

22
## 0.3.0
3-
* Updated dependencies.
3+
+ Breaking changes:
4+
- Removed class `SyntheticInput` and replaced it with the enum
5+
`BuildLocation`.
6+
- Type parameters of `MergingBuilder` now match the type parameters
7+
of its instance of `MergingGenerator`.
8+
* Fixed bug in SyntheticBuilder related to the process order of
49
* Requires SDK ^0.3.9 and analyzer ^8.2.0
5-
* Fixed bug in SyntheticBuilder related to the sorting process order of
610
dependent input files.
11+
* Updated dependencies.
12+
13+
714

815
## 0.2.8
916
* Updated dependencies

README.md

Lines changed: 20 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,10 @@
77

88
Source code generation has become an important software development tool
99
when building and maintaining a large number of data models,
10-
data access object, widgets, etc.
11-
12-
The premise of *source code generation* is that we can specify
10+
data access object, widgets, etc. The premise of *source code generation* is that we can specify
1311
(hopefully few) details and flesh out the rest of the classes,
1412
and methods during the build process.
1513

16-
The build process consists of scannig the appropriate files,
17-
extracting the required information,
18-
generating the source code, and writing the source code to certain files.
19-
The build process
20-
also entails keeping track of files changes,
21-
delete conflicting files, reporting issues and progress.
22-
23-
Source code generation using Dart relies heavily on *constants* known at compile time.
24-
Dart's static [`analyzer`][analyzer] provides access to libraries, classes,
25-
class fields, class methods, functions, variables, etc in the form of [`Elements`][Elements].
26-
Compile-time constant expressions are represented by a [`DartObject`][DartObject]
27-
and can be accessed by using [`computeConstantValue()`][computeConstantValue()] a method available for elements representing a variable.
28-
29-
In practice, we mark constant constant classes with annotations and instruct
30-
the builder to processes only the annotated objects.
31-
32-
3314
The library [`merging_builder`][merging_builder] includes the following (synthetic input) builder classes:
3415

3516
* [`MergingBuilder`][class-merging-builder] reads **several input files** and writes
@@ -57,134 +38,15 @@ To set up a build system the following steps are required:
5738

5839
2. 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].
5940

60-
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());
95-
}
96-
return result;
97-
}
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-
}
125-
126-
```
127-
</details>
128-
12941
3. 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.
13042
* The generator `AddNamesGenerator` shown below extends `MergingGenerator<List<String>, AddNames>` (see step 2).
13143
* Input sources may be specified using wildcard characters supported by [`Glob`][Glob].
13244
* 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).
13345

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>
181-
18246
4. In the package **defining** the builder, add the builder configuration for the builder `add_names_builder` (see below). The build extensions for
183-
[`MergingBuilder`][MergingBuilder] must be specified using the notation available for **synthetic input**. For example, `"$lib$"` indicates that the
47+
[`MergingBuilder`][MergingBuilder] must be specified using the notation
48+
available for **synthetic input**. For example, `"$lib$"` indicates that the
18449
input files are located in the folder `lib` or a subfolder thereof.
185-
For more information consult the section: [Writing a Builder using a synthetic input]
186-
found in the documentation of the Dart package [`build`][build].
187-
18850
```Yaml
18951
builders:
19052
add_names_builder:
@@ -201,7 +63,9 @@ found in the documentation of the Dart package [`build`][build].
20163
build_to: source
20264
```
20365

204-
5. In the package **using** the custom builder, `researcher`, add `add_names_builder` to the list of known builders. The file `build.yaml` is shown below.
66+
5. In the package **using** the custom builder, `researcher`,
67+
add `add_names_builder` to the list of known builders.
68+
The file `build.yaml` is shown below.
20569

20670
```Yaml
20771
targets:
@@ -230,19 +94,6 @@ found in the documentation of the Dart package [`build`][build].
23094
6. In the package **using** the builder, `researcher`, add `researcher_builder`
23195
and [`build_runner`][build_runner] as *dev_dependencies* in the file `pubspec.yaml`.
23296

233-
```Yaml
234-
name: researcher
235-
description:
236-
Example demonstrating how to use the library merging_builder.
237-
238-
environment:
239-
sdk: '>=2.17.0 <3.0.0'
240-
241-
dev_dependencies:
242-
build_runner: ^1.10.0
243-
researcher_builder:
244-
path: ../researcher_builder
245-
```
24697

24798
7. Initiate the build process by using the command:
24899
```console
@@ -251,24 +102,22 @@ and [`build_runner`][build_runner] as *dev_dependencies* in the file `pubspec.ya
251102

252103
## Implementation Details
253104

254-
The classes [`MergingBuilder<T, S extends SyntheticInput>`][class-merging-builder]
255-
and [`StandaloneBuilder<S extends SyntheticInput>`][class-standalone-builder]
256-
use *synthetic input* which must be specified
257-
by choosing either [`LibDir`][LibDir] or [`PackageDir`][PackageDir] as type parameter `S`.
258-
259-
[`LibDir`][LibDir] indicates that input and output files are located in the package directory `lib` or a subfolder thereof. For more information
260-
about *synthetic input* see:
261-
[Writing an Aggregate Builder](https://github.com/dart-lang/build/blob/master/docs/writing_an_aggregate_builder.md#writing-the-builder-using-a-synthetic-input).
105+
The classes [`MergingBuilder`][class-merging-builder]
106+
and [`StandaloneBuilder`][class-standalone-builder]
107+
use *synthetic input*.
262108

263-
### Class - Merging Builder
109+
### Merging Builder
264110

265111
[`MergingBuilder`][MergingBuilder] reads **several input files** and writes merged output to **one output file**.
266-
The builder provides the option to sort the input files in reverse topological order. If the input file `a.dart` includes file `b.dart` then `a.dart` will be listed *after* `b.dart`. This option may be useful when
267-
generating code that needs to list variables or call functions in order of dependence. To enable topological sorting set the constructor parameter `sortAsset: true`. Note: If sorting of input assets is enabled, input files must not include each other directly or indirectly.
112+
The builder provides the option to sort the input files in reverse topological order.
113+
If the input file `a.dart` includes file `b.dart` then `a.dart` will be listed *after* `b.dart`. This option may be useful when
114+
generating code that needs to list variables or call functions in order of dependence.
115+
To enable topological sorting set the constructor parameter `sortAsset: true`. Note: If sorting of input assets is enabled, input files must not include each other directly or indirectly.
116+
268117

269118
A conventional builder typically calls the generator method `generate` from within its `build` method to retrieve the generated source-code. [`MergingBuilder`][MergingBuilder] calls the [`MergingGenerator`][MergingGenerator] method `generateStream`. It allows the generator to pass a stream of data-type `T` to the builder, one stream item for each annotated element processed to the generator method `generateStreamItemForAnnotatedElement`.
270119

271-
The private builder method `_combineStreams` combines the streams received for each processed input file and calls the generator method `generateMergedContent`. As a result, this method has access to all stream items of type `T` generated for each annotated element in each input file. It is the task of this method to generate the merged source-code output.
120+
The private builder method `_combineStreams` combines the streams received for each processed input file and calls the generator method `generateMergedContent`. As a result, this method has access to all stream items of type `T` generated for each annotated element in each input file. It is the task of this method to generate the *merged* source-code output.
272121

273122
The figure below shows the flow of data between the builder and the generator. The data type is indicated by the starting point of the connectors. Dotted connectors represent a stream of data.
274123

@@ -277,8 +126,10 @@ The figure below shows the flow of data between the builder and the generator. T
277126

278127
### Class - Standalone Builder
279128

280-
[`StandaloneBuilder`][StandaloneBuilder] reads one or several input files and writes standalone files to a custom location.
281-
*Standalone* means the output files may be written to a custom folder and not only the extension but the
129+
[`StandaloneBuilder`][StandaloneBuilder] reads input files and writes
130+
corresponding output files to a custom location.
131+
*Standalone* means the output files may be written to a custom folder and
132+
not only the extension but the
282133
name of the output file can be configured.
283134

284135
The input file path (constructor parameter `inputFiles`) may include

0 commit comments

Comments
 (0)