Skip to content

Commit 4d7a7b0

Browse files
authored
Use a generator to create README.md (#1001)
Easier to keep things in sync!
1 parent 06f5f5f commit 4d7a7b0

File tree

8 files changed

+215
-86
lines changed

8 files changed

+215
-86
lines changed

json_serializable/README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<!-- This content is generated. See tool/readme/readme_template.md -->
12
[![Pub Package](https://img.shields.io/pub/v/json_serializable.svg)](https://pub.dev/packages/json_serializable)
23

34
Provides [Dart Build System] builders for handling JSON.
@@ -62,9 +63,8 @@ Map<String, dynamic> _$PersonToJson(Person instance) => <String, dynamic>{
6263

6364
# Running the code generator
6465

65-
Once you have added the annotations to your code you then need to run the
66-
code generator to generate the missing `.g.dart` generated dart files.
67-
66+
Once you have added the annotations to your code you then need to run the code
67+
generator to generate the missing `.g.dart` generated dart files.
6868

6969
With a Dart package, run `pub run build_runner build` in the package directory.
7070

@@ -125,21 +125,19 @@ is generated:
125125
[JsonKey.toJson]: https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
126126
[JsonKey.unknownEnumValue]: https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/unknownEnumValue.html
127127

128-
129-
> Note: every `JsonSerializable` field is configurable via `build.yaml`
130-
> see the table for the corresponding key.
131-
> If you find you want all or most of your classes with the same configuration,
132-
> it may be easier to specify values once in the YAML file. Values set
133-
> explicitly on `@JsonSerializable` take precedence over settings in
134-
> `build.yaml`.
128+
> Note: every `JsonSerializable` field is configurable via `build.yaml` – see
129+
> the table for the corresponding key. If you find you want all or most of your
130+
> classes with the same configuration, it may be easier to specify values once
131+
> in the YAML file. Values set explicitly on `@JsonSerializable` take precedence
132+
> over settings in `build.yaml`.
135133
136134
> Note: There is some overlap between fields on `JsonKey` and
137135
> `JsonSerializable`. In these cases, if a value is set explicitly via `JsonKey`
138-
> it will take precedence over any value set on `JsonSerializable`.
136+
> it will take precedence over any value set on `JsonSerializable`.
139137
140138
# Build configuration
141139

142-
Besides setting arguments on the associated annotation classes, you can also
140+
Aside from setting arguments on the associated annotation classes, you can also
143141
configure code generation by setting values in `build.yaml`.
144142

145143
```yaml
@@ -154,7 +152,7 @@ targets:
154152
# The default value for each is listed.
155153
any_map: false
156154
checked: false
157-
constructor: ''
155+
constructor: ""
158156
create_factory: true
159157
create_to_json: true
160158
disallow_unrecognized_keys: false

json_serializable/build.yaml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,21 @@ builders:
9292
build_to: source
9393
runs_before: ["json_serializable"]
9494

95-
_doc_builder:
96-
import: "tool/doc_builder.dart"
97-
builder_factories: ["docBuilder"]
98-
build_extensions: {"lib/json_serializable.dart": ["doc/doc.md"]}
95+
_api_table_builder:
96+
import: "tool/api_table_builder.dart"
97+
builder_factories: ["apiTableBuilder"]
98+
build_extensions: {"lib/json_serializable.dart": ["tool/readme/api.md"]}
9999
build_to: source
100100
auto_apply: root_package
101-
runs_before: ["json_serializable"]
102-
required_inputs: ["doc/json_annotation_version.txt"]
101+
runs_before: ["_readme_builder"]
102+
103+
_readme_builder:
104+
import: "tool/readme_builder.dart"
105+
builder_factories: ["readmeBuilder"]
106+
build_extensions: {"tool/readme/api.md": ["README.md"]}
107+
build_to: source
108+
auto_apply: root_package
109+
required_inputs: ['.dart']
103110

104111
json_serializable:
105112
import: "package:json_serializable/builder.dart"

json_serializable/test/readme_test.dart

Lines changed: 0 additions & 63 deletions
This file was deleted.

json_serializable/tool/doc_builder.dart renamed to json_serializable/tool/api_table_builder.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import 'package:source_gen/source_gen.dart';
1010
import 'package:source_helper/source_helper.dart';
1111
import 'package:yaml/yaml.dart';
1212

13-
Builder docBuilder([_]) => _DocBuilder();
13+
import 'shared.dart';
14+
15+
Builder apiTableBuilder([_]) => _ApiTableBuilder();
1416

1517
const _jsonKey = 'JsonKey';
1618
const _jsonSerializable = 'JsonSerializable';
1719

18-
class _DocBuilder extends Builder {
20+
class _ApiTableBuilder extends Builder {
1921
@override
2022
FutureOr<void> build(BuildStep buildStep) async {
2123
final lockFileAssetId = AssetId(buildStep.inputId.package, 'pubspec.lock');
@@ -102,12 +104,12 @@ class _DocBuilder extends Builder {
102104
}
103105

104106
await buildStep.writeAsString(
105-
AssetId(buildStep.inputId.package, 'doc/doc.md'), buffer.toString());
107+
AssetId(buildStep.inputId.package, readmeApiPath), buffer.toString());
106108
}
107109

108110
@override
109111
final buildExtensions = const {
110-
r'lib/json_serializable.dart': ['doc/doc.md']
112+
r'lib/json_serializable.dart': [readmeApiPath]
111113
};
112114
}
113115

File renamed without changes.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
[![Pub Package](https://img.shields.io/pub/v/json_serializable.svg)](https://pub.dev/packages/json_serializable)
2+
3+
Provides [Dart Build System] builders for handling JSON.
4+
5+
The builders generate code when they find members annotated with classes defined
6+
in [package:json_annotation].
7+
8+
- To generate to/from JSON code for a class, annotate it with
9+
`@JsonSerializable`. You can provide arguments to `JsonSerializable` to
10+
configure the generated code. You can also customize individual fields by
11+
annotating them with `@JsonKey` and providing custom arguments. See the table
12+
below for details on the [annotation values](#annotation-values).
13+
14+
- To generate a Dart field with the contents of a file containing JSON, use the
15+
`JsonLiteral` annotation.
16+
17+
## Setup
18+
19+
To configure your project for the latest released version of,
20+
`json_serializable` see the [example].
21+
22+
## Example
23+
24+
Given a library `example.dart` with an `Person` class annotated with
25+
`@JsonSerializable()`:
26+
27+
<!-- REPLACE example.dart -->
28+
29+
Building creates the corresponding part `example.g.dart`:
30+
31+
<!-- REPLACE example.g.dart -->
32+
33+
# Running the code generator
34+
35+
Once you have added the annotations to your code you then need to run the code
36+
generator to generate the missing `.g.dart` generated dart files.
37+
38+
With a Dart package, run `pub run build_runner build` in the package directory.
39+
40+
With a Flutter package, run `flutter pub run build_runner build` in your package
41+
directory.
42+
43+
# Annotation values
44+
45+
The only annotation required to use this package is `@JsonSerializable`. When
46+
applied to a class (in a correctly configured package), `toJson` and `fromJson`
47+
code will be generated when you build. There are three ways to control how code
48+
is generated:
49+
50+
1. Set properties on `@JsonSerializable`.
51+
2. Add a `@JsonKey` annotation to a field and set properties there.
52+
3. Add configuration to `build.yaml`[see below](#build-configuration).
53+
54+
<!-- REPLACE api.md -->
55+
56+
> Note: every `JsonSerializable` field is configurable via `build.yaml` – see
57+
> the table for the corresponding key. If you find you want all or most of your
58+
> classes with the same configuration, it may be easier to specify values once
59+
> in the YAML file. Values set explicitly on `@JsonSerializable` take precedence
60+
> over settings in `build.yaml`.
61+
62+
> Note: There is some overlap between fields on `JsonKey` and
63+
> `JsonSerializable`. In these cases, if a value is set explicitly via `JsonKey`
64+
> it will take precedence over any value set on `JsonSerializable`.
65+
66+
# Build configuration
67+
68+
Aside from setting arguments on the associated annotation classes, you can also
69+
configure code generation by setting values in `build.yaml`.
70+
71+
```yaml
72+
targets:
73+
$default:
74+
builders:
75+
json_serializable:
76+
options:
77+
# Options configure how source code is generated for every
78+
# `@JsonSerializable`-annotated class in the package.
79+
#
80+
# The default value for each is listed.
81+
any_map: false
82+
checked: false
83+
constructor: ""
84+
create_factory: true
85+
create_to_json: true
86+
disallow_unrecognized_keys: false
87+
explicit_to_json: false
88+
field_rename: none
89+
generic_argument_factories: false
90+
ignore_unannotated: false
91+
include_if_null: true
92+
```
93+
94+
[example]: https://github.com/google/json_serializable.dart/tree/master/example
95+
[dart build system]: https://github.com/dart-lang/build
96+
[package:json_annotation]: https://pub.dev/packages/json_annotation
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
import 'dart:async';
5+
import 'dart:convert';
6+
7+
import 'package:build/build.dart';
8+
import 'package:path/path.dart' as p;
9+
10+
import 'shared.dart';
11+
12+
Builder readmeBuilder([_]) => _ReadmeBuilder();
13+
14+
class _ReadmeBuilder extends Builder {
15+
@override
16+
FutureOr<void> build(BuildStep buildStep) async {
17+
final templateAssetId =
18+
AssetId(buildStep.inputId.package, 'tool/readme/readme_template.md');
19+
final templateAssetContent = await buildStep.readAsString(templateAssetId);
20+
21+
Future<String> getExampleContent(String fileName) async {
22+
final content = await buildStep.readAsString(
23+
AssetId(buildStep.inputId.package, p.join('example', fileName)),
24+
);
25+
26+
final lines = LineSplitter.split(content);
27+
28+
var lastHadContent = false;
29+
30+
// All lines with content, except those starting with `/`.
31+
// Also exclude blank lines that follow other blank lines
32+
final cleanedSource = lines.where((l) {
33+
if (l.startsWith(r'/')) {
34+
return false;
35+
}
36+
37+
if (l.trim().isNotEmpty) {
38+
lastHadContent = true;
39+
return true;
40+
}
41+
42+
if (lastHadContent) {
43+
lastHadContent = false;
44+
return true;
45+
}
46+
47+
return false;
48+
}).join('\n');
49+
50+
return '''
51+
```dart
52+
$cleanedSource
53+
```''';
54+
}
55+
56+
final replacements = {
57+
'api.md': await buildStep
58+
.readAsString(AssetId(buildStep.inputId.package, readmeApiPath)),
59+
'example.dart': await getExampleContent('example.dart'),
60+
'example.g.dart': await getExampleContent('example.g.dart'),
61+
};
62+
63+
final expandedContent =
64+
templateAssetContent.replaceAllMapped(_replaceRegexp, (match) {
65+
final replacementKey = match.group(1)!;
66+
return replacements[replacementKey]!.trim();
67+
}).trim();
68+
69+
await buildStep.writeAsString(
70+
AssetId(buildStep.inputId.package, _readmePath),
71+
'''
72+
<!-- This content is generated. See $_templatePath -->
73+
$expandedContent
74+
''',
75+
);
76+
}
77+
78+
@override
79+
final buildExtensions = const {
80+
readmeApiPath: [_readmePath]
81+
};
82+
}
83+
84+
const _templatePath = 'tool/readme/readme_template.md';
85+
const _readmePath = 'README.md';
86+
87+
final _replaceRegexp = RegExp(r'<!-- REPLACE ([\w\d\.]+) -->');

json_serializable/tool/shared.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import 'dart:io';
77
import 'package:build/build.dart';
88
import 'package:yaml/yaml.dart';
99

10+
const readmeApiPath = 'tool/readme/api.md';
11+
1012
// Until we have verification in pkg:build and friends
1113
// https://github.com/dart-lang/build/issues/590
1214
Builder validate(String builderName, Builder builder) {

0 commit comments

Comments
 (0)