Write snippets index file when generating docs (#25515)
diff --git a/dev/snippets/lib/main.dart b/dev/snippets/lib/main.dart
index 3f47559..997e442 100644
--- a/dev/snippets/lib/main.dart
+++ b/dev/snippets/lib/main.dart
@@ -52,6 +52,7 @@
defaultsTo: null,
help: 'The output path for the generated snippet application. Overrides '
'the naming generated by the --package/--library/--element arguments. '
+ 'Metadata will be written alongside in a .json file. '
'The basename of this argument is used as the ID',
);
parser.addOption(
@@ -113,20 +114,21 @@
template = args[_kTemplateOption].toString().replaceAll(RegExp(r'.tmpl$'), '');
}
+ final String packageName = args[_kPackageOption] != null && args[_kPackageOption].isNotEmpty ? args[_kPackageOption] : null;
+ final String libraryName = args[_kLibraryOption] != null && args[_kLibraryOption].isNotEmpty ? args[_kLibraryOption] : null;
+ final String elementName = args[_kElementOption] != null && args[_kElementOption].isNotEmpty ? args[_kElementOption] : null;
final List<String> id = <String>[];
if (args[_kOutputOption] != null) {
id.add(path.basename(path.basenameWithoutExtension(args[_kOutputOption])));
} else {
- if (args[_kPackageOption] != null &&
- args[_kPackageOption].isNotEmpty &&
- args[_kPackageOption] != 'flutter') {
- id.add(args[_kPackageOption]);
+ if (packageName != null && packageName != 'flutter') {
+ id.add(packageName);
}
- if (args[_kLibraryOption] != null && args[_kLibraryOption].isNotEmpty) {
- id.add(args[_kLibraryOption]);
+ if (libraryName != null) {
+ id.add(libraryName);
}
- if (args[_kElementOption] != null && args[_kElementOption].isNotEmpty) {
- id.add(args[_kElementOption]);
+ if (elementName != null) {
+ id.add(elementName);
}
if (id.isEmpty) {
errorExit('Unable to determine ID. At least one of --$_kPackageOption, '
@@ -142,6 +144,13 @@
template: template,
id: id.join('.'),
output: args[_kOutputOption] != null ? File(args[_kOutputOption]) : null,
+ metadata: <String, Object>{
+ 'sourcePath': environment['SOURCE_PATH'],
+ 'package': packageName,
+ 'library': libraryName,
+ 'element': elementName,
+ },
));
+
exit(0);
}
diff --git a/dev/snippets/lib/snippets.dart b/dev/snippets/lib/snippets.dart
index cb3201c..0881694 100644
--- a/dev/snippets/lib/snippets.dart
+++ b/dev/snippets/lib/snippets.dart
@@ -39,6 +39,8 @@
/// snippet.
final Configuration configuration;
+ static const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' ');
+
/// A Dart formatted used to format the snippet code and finished application
/// code.
static DartFormatter formatter = DartFormatter(pageWidth: 80, fixes: StyleFix.all);
@@ -193,7 +195,7 @@
/// The [id] is a string ID to use for the output file, and to tell the user
/// about in the `flutter create` hint. It must not be null if the [type] is
/// [SnippetType.application].
- String generate(File input, SnippetType type, {String template, String id, File output}) {
+ String generate(File input, SnippetType type, {String template, String id, File output, Map<String, Object> metadata}) {
assert(template != null || type != SnippetType.application);
assert(id != null || type != SnippetType.application);
assert(input != null);
@@ -226,6 +228,23 @@
final File outputFile = output ?? getOutputFile(id);
stderr.writeln('Writing to ${outputFile.absolute.path}');
outputFile.writeAsStringSync(app);
+
+ final File metadataFile = File(path.join(path.dirname(outputFile.path),
+ '${path.basenameWithoutExtension(outputFile.path)}.json'));
+ stderr.writeln('Writing metadata to ${metadataFile.absolute.path}');
+ final _ComponentTuple description = snippetData.firstWhere(
+ (_ComponentTuple data) => data.name == 'description',
+ orElse: () => null,
+ );
+ metadata ??= <String, Object>{};
+ metadata.addAll(<String, Object>{
+ 'id': id,
+ 'file': path.basename(outputFile.path),
+ 'description': description != null
+ ? description.mergedContent
+ : null,
+ });
+ metadataFile.writeAsStringSync(jsonEncoder.convert(metadata));
break;
case SnippetType.sample:
break;
diff --git a/dev/snippets/test/snippets_test.dart b/dev/snippets/test/snippets_test.dart
index c73e38d..9b1a07b 100644
--- a/dev/snippets/test/snippets_test.dart
+++ b/dev/snippets/test/snippets_test.dart
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:convert';
import 'dart:io' hide Platform;
import 'package:path/path.dart' as path;
@@ -111,5 +112,40 @@
'On several lines.{@inject-html}</div>\n'));
expect(html, contains('main() {'));
});
+
+ test('generates snippet application metadata', () async {
+ final File inputFile = File(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+A description of the snippet.
+
+On several lines.
+
+```code
+void main() {
+ print('The actual \$name.');
+}
+```
+''');
+
+ final File outputFile = File(path.join(tmpDir.absolute.path, 'snippet_out.dart'));
+ final File expectedMetadataFile = File(path.join(tmpDir.absolute.path, 'snippet_out.json'));
+
+ generator.generate(
+ inputFile,
+ SnippetType.application,
+ template: 'template',
+ id: 'id',
+ output: outputFile,
+ metadata: <String, Object>{'sourcePath': 'some/path.dart'},
+ );
+ expect(expectedMetadataFile.existsSync(), isTrue);
+ final Map<String, dynamic> json = jsonDecode(expectedMetadataFile.readAsStringSync());
+ expect(json['id'], equals('id'));
+ expect(json['file'], equals('snippet_out.dart'));
+ expect(json['description'], equals('A description of the snippet.\n\nOn several lines.'));
+ // Ensure any passed metadata is included in the output JSON too.
+ expect(json['sourcePath'], equals('some/path.dart'));
+ });
});
}
diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart
index 2c259cf..de3751c 100644
--- a/dev/tools/dartdoc.dart
+++ b/dev/tools/dartdoc.dart
@@ -353,6 +353,7 @@
addHtmlBaseToIndex();
changePackageToSdkInTitlebar();
putRedirectInOldIndexLocation();
+ writeSnippetsIndexFile();
print('\nDocs ready to go!');
}
@@ -407,6 +408,23 @@
File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag);
}
+
+void writeSnippetsIndexFile() {
+ final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets'));
+ if (snippetsDir.existsSync()) {
+ const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' ');
+ final Iterable<File> files = snippetsDir
+ .listSync()
+ .whereType<File>()
+ .where((File file) => path.extension(file.path) == '.json');
+ // Combine all the metadata into a single JSON array.
+ final Iterable<String> fileContents = files.map((File file) => file.readAsStringSync());
+ final List<dynamic> metadataObjects = fileContents.map<dynamic>(json.decode).toList();
+ final String jsonArray = jsonEncoder.convert(metadataObjects);
+ File('$kPublishRoot/snippets/index.json').writeAsStringSync(jsonArray);
+ }
+}
+
List<String> findPackageNames() {
return findPackages().map<String>((FileSystemEntity file) => path.basename(file.path)).toList();
}