Unverified Commit 10e4b040 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Switch document generation to use the snippets package (#87231)

Switch document generation to use the snippets package instead of the snippets code in the Flutter repo. In the process, some bugs in sample code analysis have been fixed, and I've fixed some more errors in the samples.

This will allow the snippets package to be developed separately from the Flutter repo, and reduce the code in the Flutter repo.

The snippets code is deleted in this PR.

I also converted some comments in the snippet templates to be regular comments instead of doc comments, because having a doc comment block before the imports causes the Dart import sorter to lose the comment. They should have been regular comments in the first place.

The snippets package resides in the assets-for-api-docs repo.

The sample analysis has also been converted to be run in parallel, and I've bumped the Dartdoc version to 1.0.2.
parent 0340319a
...@@ -138,7 +138,7 @@ task: ...@@ -138,7 +138,7 @@ task:
- name: docs-linux # linux-only - name: docs-linux # linux-only
environment: environment:
CPU: 4 CPU: 4
MEMORY: 8G MEMORY: 12G
only_if: "$CIRRUS_PR != ''" only_if: "$CIRRUS_PR != ''"
script: script:
- ./dev/bots/docs.sh - ./dev/bots/docs.sh
......
# This file is used by dartdoc when generating API documentation for Flutter. # This file is used by dartdoc when generating API documentation for Flutter.
dartdoc: dartdoc:
# Before you can run dartdoc, the snippets tool needs to have a snapshot built. # Before you can run dartdoc, the snippets tool needs to be
# The dev/tools/dartdoc.dart script does this automatically. # activated with "pub global activate snippets <version>"
# The dev/bots/docs.sh script does this automatically.
tools: tools:
snippet: snippet:
command: ["dev/snippets/lib/main.dart", "--type=snippet"] command: ["bin/cache/dart-sdk/bin/pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=snippet"]
description: "Creates sample code documentation output from embedded documentation samples." description: "Creates sample code documentation output from embedded documentation samples."
sample: sample:
command: ["dev/snippets/lib/main.dart", "--type=sample"] command: ["bin/cache/dart-sdk/bin/pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=sample"]
description: "Creates full application sample code documentation output from embedded documentation samples." description: "Creates full application sample code documentation output from embedded documentation samples."
dartpad: dartpad:
command: ["dev/snippets/lib/main.dart", "--type=sample", "--dartpad"] command: ["bin/cache/dart-sdk/bin/pub", "global", "run", "snippets", "--output-directory=doc/snippets", "--type=dartpad"]
description: "Creates full application sample code documentation output from embedded documentation samples and displays it in an embedded DartPad." description: "Creates full application sample code documentation output from embedded documentation samples and displays it in an embedded DartPad."
errors: errors:
# Default errors of dartdoc: # Default errors of dartdoc:
......
This diff is collapsed.
...@@ -13,14 +13,26 @@ function script_location() { ...@@ -13,14 +13,26 @@ function script_location() {
script_location="$(readlink "$script_location")" script_location="$(readlink "$script_location")"
[[ "$script_location" != /* ]] && script_location="$DIR/$script_location" [[ "$script_location" != /* ]] && script_location="$DIR/$script_location"
done done
echo "$(cd -P "$(dirname "$script_location")" >/dev/null && pwd)" cd -P "$(dirname "$script_location")" >/dev/null && pwd
} }
function generate_docs() { function generate_docs() {
# Install and activate dartdoc. # Install and activate dartdoc.
# NOTE: When updating to a new dartdoc version, please also update # NOTE: When updating to a new dartdoc version, please also update
# `dartdoc_options.yaml` to include newly introduced error and warning types. # `dartdoc_options.yaml` to include newly introduced error and warning types.
"$PUB" global activate dartdoc 1.0.0 "$PUB" global activate dartdoc 1.0.2
# Install and activate the snippets tool, which resides in the
# assets-for-api-docs repo:
# https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
# >>> If you update this version, also update it in dev/bots/analyze_sample_code.dart <<<
"$PUB" global activate snippets 0.2.2
# Install and activate the snippets tool, which resides in the
# assets-for-api-docs repo:
# https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets
# >>> If you update this version, also update it in dev/bots/analyze_sample_code.dart <<<
"$PUB" global activate snippets 0.2.1
# This script generates a unified doc set, and creates # This script generates a unified doc set, and creates
# a custom index.html, placing everything into dev/docs/doc. # a custom index.html, placing everything into dev/docs/doc.
...@@ -96,9 +108,9 @@ function move_offline_into_place() { ...@@ -96,9 +108,9 @@ function move_offline_into_place() {
mv flutter.docs.zip doc/offline/flutter.docs.zip mv flutter.docs.zip doc/offline/flutter.docs.zip
du -sh doc/offline/flutter.docs.zip du -sh doc/offline/flutter.docs.zip
if [[ "$LUCI_BRANCH" == "stable" ]]; then if [[ "$LUCI_BRANCH" == "stable" ]]; then
echo -e "<entry>\n <version>${FLUTTER_VERSION}</version>\n <url>https://api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml echo -e "<entry>\n <version>${FLUTTER_VERSION_STRING}</version>\n <url>https://api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml
else else
echo -e "<entry>\n <version>${FLUTTER_VERSION}</version>\n <url>https://master-api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml echo -e "<entry>\n <version>${FLUTTER_VERSION_STRING}</version>\n <url>https://master-api.flutter.dev/offline/flutter.docset.tar.gz</url>\n</entry>" > doc/offline/flutter.xml
fi fi
mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz
du -sh doc/offline/flutter.docset.tar.gz du -sh doc/offline/flutter.docset.tar.gz
...@@ -125,9 +137,11 @@ DART="$DART_BIN/dart" ...@@ -125,9 +137,11 @@ DART="$DART_BIN/dart"
PUB="$DART_BIN/pub" PUB="$DART_BIN/pub"
export PATH="$FLUTTER_BIN:$DART_BIN:$PATH" export PATH="$FLUTTER_BIN:$DART_BIN:$PATH"
# Make sure dart is installed by invoking flutter to download it. # Make sure dart is installed by invoking Flutter to download it.
"$FLUTTER" --version # This also creates the 'version' file.
FLUTTER_VERSION=$(cat "$FLUTTER_ROOT/version") FLUTTER_VERSION=$("$FLUTTER" --version --machine)
export FLUTTER_VERSION
FLUTTER_VERSION_STRING=$(cat "$FLUTTER_ROOT/version")
# If the pub cache directory exists in the root, then use that. # If the pub cache directory exists in the root, then use that.
FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache" FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache"
......
...@@ -746,7 +746,6 @@ Future<void> _runFrameworkTests() async { ...@@ -746,7 +746,6 @@ Future<void> _runFrameworkTests() async {
print('${green}Running package tests$reset for directories other than packages/flutter'); print('${green}Running package tests$reset for directories other than packages/flutter');
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots')); await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'));
await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209 await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209
await _pubRunTest(path.join(flutterRoot, 'dev', 'snippets'));
// TODO(fujino): Move this to its own test shard // TODO(fujino): Move this to its own test shard
await _pubRunTest(path.join(flutterRoot, 'dev', 'conductor'), forceSingleCore: true); await _pubRunTest(path.join(flutterRoot, 'dev', 'conductor'), forceSingleCore: true);
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'));
......
...@@ -11,11 +11,13 @@ library dart.ui; ...@@ -11,11 +11,13 @@ library dart.ui;
/// Annotation used by Flutter's Dart compiler to indicate that an /// Annotation used by Flutter's Dart compiler to indicate that an
/// [Object.toString] override should not be replaced with a supercall. /// [Object.toString] override should not be replaced with a supercall.
/// ///
/// {@tool sample} /// {@tool sample --template=stateless_widget_material}
/// A sample if using keepToString to prevent replacement by a supercall. /// A sample if using keepToString to prevent replacement by a supercall.
/// ///
/// ```dart /// ```dart
/// class MyStringBuffer { /// class MyStringBuffer {
/// error;
///
/// StringBuffer _buffer = StringBuffer(); /// StringBuffer _buffer = StringBuffer();
/// ///
/// @keepToString /// @keepToString
......
...@@ -20,11 +20,10 @@ void main() { ...@@ -20,11 +20,10 @@ void main() {
<String>['analyze_sample_code.dart', '--no-include-dart-ui', 'test/analyze-sample-code-test-input'], <String>['analyze_sample_code.dart', '--no-include-dart-ui', 'test/analyze-sample-code-test-input'],
); );
final List<String> stdoutLines = process.stdout.toString().split('\n'); final List<String> stdoutLines = process.stdout.toString().split('\n');
final List<String> stderrLines = process.stderr.toString().split('\n') final List<String> stderrLines = process.stderr.toString().split('\n');
..removeWhere((String line) => line.startsWith('Analyzer output:') || line.startsWith('Building flutter tool...'));
expect(process.exitCode, isNot(equals(0))); expect(process.exitCode, isNot(equals(0)));
expect(stderrLines, <String>[ expect(stderrLines, containsAll(<String>[
'In sample starting at dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:125: child: Text(title),', 'In sample starting at dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:125: child: Text(title),',
">>> error: The final variable 'title' can't be read because it is potentially unassigned at this point (read_potentially_unassigned_final)", ">>> error: The final variable 'title' can't be read because it is potentially unassigned at this point (read_potentially_unassigned_final)",
'dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:30:9: new Opacity(', 'dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:30:9: new Opacity(',
'>>> info: Unnecessary new keyword (unnecessary_new)', '>>> info: Unnecessary new keyword (unnecessary_new)',
...@@ -38,32 +37,35 @@ void main() { ...@@ -38,32 +37,35 @@ void main() {
">>> error: A value of type 'Null' can't be assigned to a variable of type 'int' (invalid_assignment)", ">>> error: A value of type 'Null' can't be assigned to a variable of type 'int' (invalid_assignment)",
'dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:120:24: const SizedBox(),', 'dev/bots/test/analyze-sample-code-test-input/known_broken_documentation.dart:120:24: const SizedBox(),',
'>>> error: Unexpected comma at end of sample code. (missing_identifier)', '>>> error: Unexpected comma at end of sample code. (missing_identifier)',
'',
'Found 2 sample code errors.', 'Found 2 sample code errors.',
'' ]));
]); expect(stdoutLines, containsAll(<String>[
expect(stdoutLines, <String>[
'Found 9 snippet code blocks, 0 sample code sections, and 2 dartpad sections.', 'Found 9 snippet code blocks, 0 sample code sections, and 2 dartpad sections.',
'Starting analysis of code samples.', 'Starting analysis of code samples.',
'', ]));
]);
}); });
test('Analyzes dart:ui code', () { test('Analyzes dart:ui code', () {
final ProcessResult process = Process.runSync( final ProcessResult process = Process.runSync(
'../../bin/cache/dart-sdk/bin/dart', '../../bin/cache/dart-sdk/bin/dart',
<String>[ <String>[
'analyze_sample_code.dart', 'analyze_sample_code.dart',
'--dart-ui-location', '--dart-ui-location=test/analyze-sample-code-test-dart-ui',
'test/analyze-sample-code-test-dart-ui',
'test/analyze-sample-code-test-input', 'test/analyze-sample-code-test-input',
], ],
); );
final List<String> stdoutLines = process.stdout.toString().split('\n'); final List<String> stdoutLines = process.stdout.toString().split('\n');
final List<String> stderrLines = process.stderr.toString().split('\n');
expect(process.exitCode, isNot(equals(0))); expect(process.exitCode, isNot(equals(0)));
expect(stdoutLines, equals(<String>[ expect(stderrLines, containsAll(<String>[
'In sample starting at dev/bots/test/analyze-sample-code-test-dart-ui/ui.dart:15:class MyStatelessWidget extends StatelessWidget {',
">>> error: Missing concrete implementation of 'StatelessWidget.build' (non_abstract_class_inherits_abstract_member)",
'In sample starting at dev/bots/test/analyze-sample-code-test-dart-ui/ui.dart:15:class MyStringBuffer {',
">>> error: Classes can't be declared inside other classes (class_in_class)",
]));
expect(stdoutLines, containsAll(<String>[
// There is one sample code section in the test's dummy dart:ui code. // There is one sample code section in the test's dummy dart:ui code.
'Found 9 snippet code blocks, 1 sample code sections, and 2 dartpad sections.', 'Found 9 snippet code blocks, 1 sample code sections, and 2 dartpad sections.',
'', 'Starting analysis of code samples.',
])); ]));
}); });
} }
...@@ -8,18 +8,6 @@ ...@@ -8,18 +8,6 @@
<i class="material-icons copy-image">link</i> <i class="material-icons copy-image">link</i>
</a> </a>
</div> </div>
<div class="snippet-buttons">
<script>var visibleSnippet{{serial}} = "longSnippet{{serial}}";</script>
<button id="longSnippet{{serial}}Button"
onclick="visibleSnippet{{serial}} = showSnippet('longSnippet{{serial}}', visibleSnippet{{serial}});"
selected>
Interactive App
</button>
<button id="shortSnippet{{serial}}Button"
onclick="visibleSnippet{{serial}} = showSnippet('shortSnippet{{serial}}', visibleSnippet{{serial}});">
Sample code
</button>
</div>
<div class="snippet-container"> <div class="snippet-container">
<div class="snippet" id="longSnippet{{serial}}"> <div class="snippet" id="longSnippet{{serial}}">
{{description}} {{description}}
...@@ -28,15 +16,5 @@ ...@@ -28,15 +16,5 @@
<span class="snippet-create-command">flutter create --sample={{id}} mysample</span> <span class="snippet-create-command">flutter create --sample={{id}} mysample</span>
</div> </div>
</div> </div>
<div class="snippet" id="shortSnippet{{serial}}" hidden>
{{description}}
<div class="copyable-container">
<button class="copy-button-overlay copy-button" title="Copy to clipboard"
onclick="copyTextToClipboard(visibleSnippet{{serial}});">
<i class="material-icons copy-image">assignment</i>
</button>
<pre class="language-{{language}}"><code class="language-{{language}}">{{code}}</code></pre>
</div>
</div>
</div> </div>
{@end-inject-html} {@end-inject-html}
...@@ -8,9 +8,6 @@ ...@@ -8,9 +8,6 @@
<i class="material-icons copy-image">link</i> <i class="material-icons copy-image">link</i>
</a> </a>
</div> </div>
<div class="snippet-buttons">
<button id="shortSnippet{{serial}}Button" selected>Sample</button>
</div>
<div class="snippet-container"> <div class="snippet-container">
<div class="snippet">{{description}} <div class="snippet">{{description}}
<div class="copyable-container"> <div class="copyable-container">
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -35,5 +35,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -35,5 +35,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -39,5 +39,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -39,5 +39,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -37,5 +37,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -37,5 +37,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin. /// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin { class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -37,5 +37,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -37,5 +37,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin. /// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin { class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -39,5 +39,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -39,5 +39,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -41,5 +41,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -41,5 +41,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> { class _MyStatefulWidgetState extends State<MyStatefulWidget> {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
......
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget { ...@@ -36,5 +36,5 @@ class MyStatefulWidget extends StatefulWidget {
/// This is the private State class that goes with MyStatefulWidget. /// This is the private State class that goes with MyStatefulWidget.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin. /// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin { class _MyStatefulWidgetState extends State<MyStatefulWidget> with TickerProviderStateMixin {
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -30,5 +30,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -30,5 +30,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -35,5 +35,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -35,5 +35,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -32,5 +32,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -35,5 +35,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -35,5 +35,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
/// Flutter code sample for {{element}} // Flutter code sample for {{element}}
//
{{description}} {{description}}
{{code-dartImports}} {{code-dartImports}}
...@@ -37,5 +37,5 @@ class MyStatelessWidget extends StatelessWidget { ...@@ -37,5 +37,5 @@ class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key); const MyStatelessWidget({Key? key}) : super(key: key);
@override @override
{{code}} {{code}}
} }
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io' hide Platform;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
/// What type of snippet to produce.
enum SnippetType {
/// Produces a snippet that includes the code interpolated into an application
/// template.
sample,
/// Produces a nicely formatted sample code, but no application.
snippet,
}
/// Return the name of an enum item.
String getEnumName(dynamic enumItem) {
final String name = '$enumItem';
final int index = name.indexOf('.');
return index == -1 ? name : name.substring(index + 1);
}
/// A class to compute the configuration of the snippets input and output
/// locations based in the current location of the snippets main.dart.
class Configuration {
Configuration({required this.flutterRoot}) : assert(flutterRoot != null);
final Directory flutterRoot;
/// This is the configuration directory for the snippets system, containing
/// the skeletons and templates.
@visibleForTesting
Directory get configDirectory {
_configPath ??= Directory(
path.canonicalize(path.join(flutterRoot.absolute.path, 'dev', 'snippets', 'config')));
return _configPath!;
}
// Nullable so that we can use it as a lazy cache.
Directory? _configPath;
/// This is where the snippets themselves will be written, in order to be
/// uploaded to the docs site.
Directory get outputDirectory {
_docsDirectory ??= Directory(
path.canonicalize(path.join(flutterRoot.absolute.path, 'dev', 'docs', 'doc', 'snippets')));
return _docsDirectory!;
}
// Nullable so that we can use it as a lazy cache.
Directory? _docsDirectory;
/// This makes sure that the output directory exists.
void createOutputDirectory() {
if (!outputDirectory.existsSync()) {
outputDirectory.createSync(recursive: true);
}
}
/// The directory containing the HTML skeletons to be filled out with metadata
/// and returned to dartdoc for insertion in the output.
Directory get skeletonsDirectory => Directory(path.join(configDirectory.path,'skeletons'));
/// The directory containing the code templates that can be referenced by the
/// dartdoc.
Directory get templatesDirectory => Directory(path.join(configDirectory.path, 'templates'));
/// Gets the skeleton file to use for the given [SnippetType] and DartPad preference.
File getHtmlSkeletonFile(SnippetType type, {bool showDartPad = false}) {
assert(!showDartPad || type == SnippetType.sample,
'Only application snippets work with dartpad.');
final String filename =
'${showDartPad ? 'dartpad-' : ''}${getEnumName(type)}.html';
return File(path.join(skeletonsDirectory.path, filename));
}
}
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io' show exit, stderr, stdout, File, ProcessResult;
import 'package:args/args.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'configuration.dart';
import 'snippets.dart';
const String _kSerialOption = 'serial';
const String _kElementOption = 'element';
const String _kHelpOption = 'help';
const String _kInputOption = 'input';
const String _kLibraryOption = 'library';
const String _kOutputOption = 'output';
const String _kPackageOption = 'package';
const String _kTemplateOption = 'template';
const String _kTypeOption = 'type';
const String _kShowDartPad = 'dartpad';
class GitStatusFailed implements Exception {
GitStatusFailed(this.gitResult);
final ProcessResult gitResult;
@override
String toString() => 'git status exited with a non-zero exit code: ${gitResult.exitCode}:\n${gitResult.stderr}\n${gitResult.stdout}';
}
/// Get the name of the channel these docs are from.
///
/// First check env variable LUCI_BRANCH, then refer to the currently
/// checked out git branch.
String getChannelName({
@visibleForTesting
Platform platform = const LocalPlatform(),
@visibleForTesting
ProcessManager processManager = const LocalProcessManager(),
}) {
final String? envReleaseChannel = platform.environment['LUCI_BRANCH']?.trim();
if (<String>['master', 'stable'].contains(envReleaseChannel)) {
return envReleaseChannel!;
}
final RegExp gitBranchRegexp = RegExp(r'^## (?<branch>.*)');
final ProcessResult gitResult = processManager.runSync(<String>['git', 'status', '-b', '--porcelain'],
environment: <String, String>{
'GIT_TRACE': '2',
'GIT_TRACE_SETUP': '2'
},
includeParentEnvironment: true
);
if (gitResult.exitCode != 0) {
throw GitStatusFailed(gitResult);
}
final RegExpMatch? gitBranchMatch = gitBranchRegexp.firstMatch((gitResult.stdout as String).trim().split('\n').first);
return gitBranchMatch == null ? '<unknown>' : gitBranchMatch.namedGroup('branch')!.split('...').first;
}
// This is a hack to workaround the fact that git status inexplicably fails
// (random non-zero error code) about 2% of the time.
String getChannelNameWithRetries() {
int retryCount = 0;
while(retryCount < 2) {
try {
return getChannelName();
} on GitStatusFailed catch (e) {
retryCount += 1;
stderr.write('git status failed, retrying ($retryCount)\nError report:\n$e');
}
}
return getChannelName();
}
/// Generates snippet dartdoc output for a given input, and creates any sample
/// applications needed by the snippet.
void main(List<String> argList) {
const Platform platform = LocalPlatform();
final Map<String, String> environment = platform.environment;
final ArgParser parser = ArgParser();
final List<String> snippetTypes =
SnippetType.values.map<String>((SnippetType type) => getEnumName(type)).toList();
parser.addOption(
_kTypeOption,
defaultsTo: getEnumName(SnippetType.sample),
allowed: snippetTypes,
allowedHelp: <String, String>{
getEnumName(SnippetType.sample):
'Produce a code sample application complete with embedding the sample in an '
'application template.',
getEnumName(SnippetType.snippet):
'Produce a nicely formatted piece of sample code. Does not embed the '
'sample into an application template.',
},
help: 'The type of snippet to produce.',
);
parser.addOption(
_kTemplateOption,
defaultsTo: null,
help: 'The name of the template to inject the code into.',
);
parser.addOption(
_kOutputOption,
defaultsTo: null,
help: 'The output path for the generated sample 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(
_kInputOption,
defaultsTo: environment['INPUT'],
help: 'The input file containing the sample code to inject.',
);
parser.addOption(
_kPackageOption,
defaultsTo: environment['PACKAGE_NAME'],
help: 'The name of the package that this sample belongs to.',
);
parser.addOption(
_kLibraryOption,
defaultsTo: environment['LIBRARY_NAME'],
help: 'The name of the library that this sample belongs to.',
);
parser.addOption(
_kElementOption,
defaultsTo: environment['ELEMENT_NAME'],
help: 'The name of the element that this sample belongs to.',
);
parser.addOption(
_kSerialOption,
defaultsTo: environment['INVOCATION_INDEX'],
help: 'A unique serial number for this snippet tool invocation.',
);
parser.addFlag(
_kHelpOption,
defaultsTo: false,
negatable: false,
help: 'Prints help documentation for this command',
);
parser.addFlag(
_kShowDartPad,
defaultsTo: false,
negatable: false,
help: "Indicates whether DartPad should be included in the sample's "
'final HTML output. This flag only applies when the type parameter is '
'"sample".',
);
final ArgResults args = parser.parse(argList);
if (args[_kHelpOption] as bool) {
stderr.writeln(parser.usage);
exit(0);
}
final SnippetType snippetType = SnippetType.values
.firstWhere((SnippetType type) => getEnumName(type) == args[_kTypeOption]);
if (args[_kShowDartPad] == true && snippetType != SnippetType.sample) {
errorExit('${args[_kTypeOption]} was selected, but the --dartpad flag is only valid '
'for application sample code.');
}
if (args[_kInputOption] == null) {
stderr.writeln(parser.usage);
errorExit('The --$_kInputOption option must be specified, either on the command '
'line, or in the INPUT environment variable.');
}
final File input = File(args['input'] as String);
if (!input.existsSync()) {
errorExit('The input file ${input.path} does not exist.');
}
String? template;
if (snippetType == SnippetType.sample) {
final String templateArg = args[_kTemplateOption] as String;
if (templateArg == null || templateArg.isEmpty) {
stderr.writeln(parser.usage);
errorExit('The --$_kTemplateOption option must be specified on the command '
'line for application samples.');
}
template = templateArg.replaceAll(RegExp(r'.tmpl$'), '');
}
final String packageName = args[_kPackageOption] as String? ?? '';
final String libraryName = args[_kLibraryOption] as String? ?? '';
final String elementName = args[_kElementOption] as String? ?? '';
final String serial = args[_kSerialOption] as String? ?? '';
final List<String> id = <String>[];
if (args[_kOutputOption] != null) {
id.add(path.basename(path.basenameWithoutExtension(args[_kOutputOption] as String)));
} else {
if (packageName.isNotEmpty && packageName != 'flutter') {
id.add(packageName);
}
if (libraryName.isNotEmpty) {
id.add(libraryName);
}
if (elementName.isNotEmpty) {
id.add(elementName);
}
if (serial.isNotEmpty) {
id.add(serial);
}
if (id.isEmpty) {
errorExit('Unable to determine ID. At least one of --$_kPackageOption, '
'--$_kLibraryOption, --$_kElementOption, -$_kSerialOption, or the environment variables '
'PACKAGE_NAME, LIBRARY_NAME, ELEMENT_NAME, or INVOCATION_INDEX must be non-empty.');
}
}
final SnippetGenerator generator = SnippetGenerator();
stdout.write(generator.generate(
input,
snippetType,
showDartPad: args[_kShowDartPad] as bool,
template: template,
output: args[_kOutputOption] != null ? File(args[_kOutputOption] as String) : null,
metadata: <String, Object?>{
'sourcePath': environment['SOURCE_PATH'],
'sourceLine': environment['SOURCE_LINE'] != null
? int.tryParse(environment['SOURCE_LINE']!)
: null,
'id': id.join('.'),
'channel': getChannelNameWithRetries(),
'serial': serial,
'package': packageName,
'library': libraryName,
'element': elementName,
},
));
exit(0);
}
This diff is collapsed.
name: snippets
version: 0.1.0
description: A code snippet dartdoc extension for Flutter API docs.
homepage: https://github.com/flutter/flutter
environment:
sdk: ">=2.12.1 <3.0.0"
dartdoc:
# Exclude this package from the hosted API docs (Ironically...).
nodoc: true
dependencies:
args: 2.2.0
dart_style: 2.0.3
meta: 1.7.0
platform: 3.0.0
process: 4.2.3
_fe_analyzer_shared: 23.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
analyzer: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
cli_util: 0.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.15.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
file: 6.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_config: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
path: 1.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pedantic: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 2.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
test: 1.17.10
boolean_selector: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
coverage: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
frontend_server_client: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 3.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 4.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pool: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 1.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_packages_handler: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_static: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_api: 0.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service: 7.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
webkit_inspection_protocol: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
executables:
snippets: null
boolean_selector: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http: 0.12.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 0.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
matcher: 0.12.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_resolver: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pool: 1.3.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 0.7.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_packages_handler: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 0.2.2+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 1.6.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
# PUBSPEC CHECKSUM: c51d
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:snippets/configuration.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
group('Configuration', () {
late Configuration config;
setUp(() {
config = Configuration(flutterRoot: Directory('/flutter sdk'));
});
test('config directory is correct', () async {
expect(config.configDirectory.path,
matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config')));
});
test('output directory is correct', () async {
expect(config.outputDirectory.path,
matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]docs[/\\]doc[/\\]snippets')));
});
test('skeleton directory is correct', () async {
expect(config.skeletonsDirectory.path,
matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons')));
});
test('templates directory is correct', () async {
expect(config.templatesDirectory.path,
matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]templates')));
});
test('html skeleton file for sample is correct', () async {
expect(
config.getHtmlSkeletonFile(SnippetType.snippet).path,
matches(RegExp(
r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]snippet.html')));
});
test('html skeleton file for app with no dartpad is correct', () async {
expect(
config.getHtmlSkeletonFile(SnippetType.sample).path,
matches(RegExp(
r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]sample.html')));
});
test('html skeleton file for app with dartpad is correct', () async {
expect(
config.getHtmlSkeletonFile(SnippetType.sample, showDartPad: true).path,
matches(RegExp(
r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]dartpad-sample.html')));
});
});
}
This diff is collapsed.
...@@ -118,14 +118,25 @@ Future<void> main(List<String> arguments) async { ...@@ -118,14 +118,25 @@ Future<void> main(List<String> arguments) async {
'dartdoc', 'dartdoc',
]; ];
// Verify which version of dartdoc we're using. // Verify which version of snippets and dartdoc we're using.
final ProcessResult result = Process.runSync( final ProcessResult snippetsResult = Process.runSync(
pubExecutable, pubExecutable,
<String>[...dartdocBaseArgs, '--version'], <String>[
'global',
'list',
],
workingDirectory: kDocsRoot, workingDirectory: kDocsRoot,
environment: pubEnvironment, environment: pubEnvironment,
stdoutEncoding: utf8,
); );
print('\n${result.stdout}flutter version: $version\n'); print('');
final Iterable<RegExpMatch> versionMatches = RegExp(r'^(?<name>snippets|dartdoc) (?<version>[^\s]+)', multiLine: true)
.allMatches(snippetsResult.stdout as String);
for (final RegExpMatch match in versionMatches) {
print('${match.namedGroup('name')} version: ${match.namedGroup('version')}');
}
print('flutter version: $version\n');
// Dartdoc warnings and errors in these packages are considered fatal. // Dartdoc warnings and errors in these packages are considered fatal.
// All packages owned by flutter should be in the list. // All packages owned by flutter should be in the list.
......
...@@ -32,7 +32,7 @@ import 'theme.dart'; ...@@ -32,7 +32,7 @@ import 'theme.dart';
/// // Uncomment to change the background color /// // Uncomment to change the background color
/// // backgroundColor: CupertinoColors.systemPink, /// // backgroundColor: CupertinoColors.systemPink,
/// navigationBar: const CupertinoNavigationBar( /// navigationBar: const CupertinoNavigationBar(
/// middle: const Text('Sample Code'), /// middle: Text('Sample Code'),
/// ), /// ),
/// child: ListView( /// child: ListView(
/// children: <Widget>[ /// children: <Widget>[
......
...@@ -1410,7 +1410,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -1410,7 +1410,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
/// child: SizedBox( /// child: SizedBox(
/// height: 20, /// height: 20,
/// child: Center( /// child: Center(
/// child: const Text('Scroll to see the SliverAppBar in effect.'), /// child: Text('Scroll to see the SliverAppBar in effect.'),
/// ), /// ),
/// ), /// ),
/// ), /// ),
......
...@@ -382,7 +382,7 @@ class DataCell { ...@@ -382,7 +382,7 @@ class DataCell {
/// child: DataTable( /// child: DataTable(
/// columns: const <DataColumn>[ /// columns: const <DataColumn>[
/// DataColumn( /// DataColumn(
/// label: const Text('Number'), /// label: Text('Number'),
/// ), /// ),
/// ], /// ],
/// rows: List<DataRow>.generate( /// rows: List<DataRow>.generate(
......
...@@ -2426,7 +2426,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ...@@ -2426,7 +2426,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat
/// hintText: 'Hint Text', /// hintText: 'Hint Text',
/// helperText: 'Helper Text', /// helperText: 'Helper Text',
/// counterText: '0 characters', /// counterText: '0 characters',
/// border: const OutlineInputBorder(), /// border: OutlineInputBorder(),
/// ), /// ),
/// ); /// );
/// } /// }
......
...@@ -281,7 +281,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter { ...@@ -281,7 +281,7 @@ class _LinearProgressIndicatorPainter extends CustomPainter {
/// children: <Widget>[ /// children: <Widget>[
/// const Text( /// const Text(
/// 'Linear progress indicator with a fixed color', /// 'Linear progress indicator with a fixed color',
/// style: const TextStyle(fontSize: 20), /// style: TextStyle(fontSize: 20),
/// ), /// ),
/// LinearProgressIndicator( /// LinearProgressIndicator(
/// value: controller.value, /// value: controller.value,
......
...@@ -339,10 +339,10 @@ abstract class Gradient { ...@@ -339,10 +339,10 @@ abstract class Gradient {
/// Widget build(BuildContext context) { /// Widget build(BuildContext context) {
/// return Container( /// return Container(
/// decoration: const BoxDecoration( /// decoration: const BoxDecoration(
/// gradient: const LinearGradient( /// gradient: LinearGradient(
/// begin: Alignment.topLeft, /// begin: Alignment.topLeft,
/// end: Alignment(0.8, 0.0), // 10% of the width, so there are ten blinds. /// end: Alignment(0.8, 0.0), // 10% of the width, so there are ten blinds.
/// colors: const <Color>[Color(0xffee0000), Color(0xffeeee00)], // red to yellow /// colors: <Color>[Color(0xffee0000), Color(0xffeeee00)], // red to yellow
/// tileMode: TileMode.repeated, // repeats the gradient over the canvas /// tileMode: TileMode.repeated, // repeats the gradient over the canvas
/// ), /// ),
/// ), /// ),
......
...@@ -444,7 +444,7 @@ typedef AutocompleteOptionToString<T extends Object> = String Function(T option) ...@@ -444,7 +444,7 @@ typedef AutocompleteOptionToString<T extends Object> = String Function(T option)
/// ), /// ),
/// ElevatedButton( /// ElevatedButton(
/// onPressed: () { /// onPressed: () {
/// FocusScope.of(context).requestFocus(new FocusNode()); /// FocusScope.of(context).unfocus();
/// if (!_formKey.currentState!.validate()) { /// if (!_formKey.currentState!.validate()) {
/// return; /// return;
/// } /// }
......
...@@ -901,7 +901,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { ...@@ -901,7 +901,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
/// return const SizedBox( /// return const SizedBox(
/// width: 200, /// width: 200,
/// child: Padding( /// child: Padding(
/// padding: const EdgeInsets.all(8.0), /// padding: EdgeInsets.all(8.0),
/// child: TextField( /// child: TextField(
/// decoration: InputDecoration(border: OutlineInputBorder()), /// decoration: InputDecoration(border: OutlineInputBorder()),
/// ), /// ),
......
...@@ -4433,7 +4433,7 @@ typedef ErrorWidgetBuilder = Widget Function(FlutterErrorDetails details); ...@@ -4433,7 +4433,7 @@ typedef ErrorWidgetBuilder = Widget Function(FlutterErrorDetails details);
/// alignment: Alignment.center, /// alignment: Alignment.center,
/// child: const Text( /// child: const Text(
/// 'Error!', /// 'Error!',
/// style: const TextStyle(color: Colors.yellow), /// style: TextStyle(color: Colors.yellow),
/// textDirection: TextDirection.ltr, /// textDirection: TextDirection.ltr,
/// ), /// ),
/// ); /// );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment