mirror of
https://github.com/flutter/flutter
synced 2024-09-12 21:01:59 +00:00
Adds DartPad option to the DartDoc snippet generator. (#39924)
This commit is contained in:
parent
440a911034
commit
691977755c
|
@ -9,3 +9,6 @@ dartdoc:
|
|||
sample:
|
||||
command: ["dev/snippets/lib/main.dart", "--type=sample"]
|
||||
description: "Creates sample code documentation output from embedded documentation samples."
|
||||
dartpad:
|
||||
command: ["dev/snippets/lib/main.dart", "--type=application", "--dartpad"]
|
||||
description: "Creates sample code documentation output from embedded documentation samples and displays it in an embedded DartPad."
|
||||
|
|
|
@ -83,6 +83,11 @@
|
|||
font-family: courier, lucidia;
|
||||
}
|
||||
|
||||
.snippet-dartpad {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.anchor-container {
|
||||
position: relative;
|
||||
}
|
||||
|
|
38
dev/snippets/config/skeletons/dartpad-application.html
Normal file
38
dev/snippets/config/skeletons/dartpad-application.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
{@inject-html}
|
||||
<a name="{{id}}"></a>
|
||||
<div class="anchor-container">
|
||||
<a class="anchor-button-overlay anchor-button" title="Copy link to clipboard"
|
||||
onmouseenter="fixHref(this, '{{id}}');"
|
||||
onclick="fixHref(this, '{{id}}'); copyStringToClipboard(this.href);"
|
||||
href="#">
|
||||
<i class="material-icons copy-image">link</i>
|
||||
</a>
|
||||
</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" id="longSnippet{{serial}}">
|
||||
<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}"></iframe>
|
||||
</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>
|
||||
{@end-inject-html}
|
|
@ -67,8 +67,12 @@ class Configuration {
|
|||
/// dartdoc.
|
||||
Directory get templatesDirectory => Directory(path.join(configDirectory.path, 'templates'));
|
||||
|
||||
/// Gets the skeleton file to use for the given [SnippetType].
|
||||
File getHtmlSkeletonFile(SnippetType type) {
|
||||
return File(path.join(skeletonsDirectory.path, '${getEnumName(type)}.html'));
|
||||
/// Gets the skeleton file to use for the given [SnippetType] and DartPad preference.
|
||||
File getHtmlSkeletonFile(SnippetType type, {bool showDartPad = false}) {
|
||||
assert(!showDartPad || type == SnippetType.application,
|
||||
'Only application snippets work with dartpad.');
|
||||
final String filename =
|
||||
'${showDartPad ? 'dartpad-' : ''}${getEnumName(type)}.html';
|
||||
return File(path.join(skeletonsDirectory.path, filename));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ const String _kOutputOption = 'output';
|
|||
const String _kPackageOption = 'package';
|
||||
const String _kTemplateOption = 'template';
|
||||
const String _kTypeOption = 'type';
|
||||
const String _kShowDartPad = 'dartpad';
|
||||
|
||||
/// Generates snippet dartdoc output for a given input, and creates any sample
|
||||
/// applications needed by the snippet.
|
||||
|
@ -87,6 +88,14 @@ void main(List<String> argList) {
|
|||
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 snippet\'s '
|
||||
'final HTML output. This flag only applies when the type parameter is '
|
||||
'"application".',
|
||||
);
|
||||
|
||||
final ArgResults args = parser.parse(argList);
|
||||
|
||||
|
@ -99,6 +108,11 @@ void main(List<String> argList) {
|
|||
.firstWhere((SnippetType type) => getEnumName(type) == args[_kTypeOption], orElse: () => null);
|
||||
assert(snippetType != null, "Unable to find '${args[_kTypeOption]}' in SnippetType enum.");
|
||||
|
||||
if (args[_kShowDartPad] == true && snippetType != SnippetType.application) {
|
||||
errorExit('${args[_kTypeOption]} was selected, but the --dartpad flag is only valid '
|
||||
'for application snippets.');
|
||||
}
|
||||
|
||||
if (args[_kInputOption] == null) {
|
||||
stderr.writeln(parser.usage);
|
||||
errorExit('The --$_kInputOption option must be specified, either on the command '
|
||||
|
@ -151,6 +165,7 @@ void main(List<String> argList) {
|
|||
stdout.write(generator.generate(
|
||||
input,
|
||||
snippetType,
|
||||
showDartPad: args[_kShowDartPad],
|
||||
template: template,
|
||||
output: args[_kOutputOption] != null ? File(args[_kOutputOption]) : null,
|
||||
metadata: <String, Object>{
|
||||
|
|
|
@ -202,6 +202,11 @@ class SnippetGenerator {
|
|||
/// The [type] is the type of snippet to create: either a
|
||||
/// [SnippetType.application] or a [SnippetType.sample].
|
||||
///
|
||||
/// [showDartPad] indicates whether DartPad should be shown where possible.
|
||||
/// Currently, this value only has an effect if [type] is
|
||||
/// [SnippetType.application], in which case an alternate skeleton file is
|
||||
/// used to create the final HTML output.
|
||||
///
|
||||
/// The [template] must not be null if the [type] is
|
||||
/// [SnippetType.application], and specifies the name of the template to use
|
||||
/// for the application code.
|
||||
|
@ -212,6 +217,7 @@ class SnippetGenerator {
|
|||
String generate(
|
||||
File input,
|
||||
SnippetType type, {
|
||||
bool showDartPad = false,
|
||||
String template,
|
||||
File output,
|
||||
@required Map<String, Object> metadata,
|
||||
|
@ -219,6 +225,8 @@ class SnippetGenerator {
|
|||
assert(template != null || type != SnippetType.application);
|
||||
assert(metadata != null && metadata['id'] != null);
|
||||
assert(input != null);
|
||||
assert(!showDartPad || type == SnippetType.application,
|
||||
'Only application snippets work with dartpad.');
|
||||
final List<_ComponentTuple> snippetData = parseInput(_loadFileAsUtf8(input));
|
||||
switch (type) {
|
||||
case SnippetType.application:
|
||||
|
@ -266,7 +274,8 @@ class SnippetGenerator {
|
|||
case SnippetType.sample:
|
||||
break;
|
||||
}
|
||||
final String skeleton = _loadFileAsUtf8(configuration.getHtmlSkeletonFile(type));
|
||||
final String skeleton =
|
||||
_loadFileAsUtf8(configuration.getHtmlSkeletonFile(type, showDartPad: showDartPad));
|
||||
return interpolateSkeleton(type, snippetData, skeleton, metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,11 +31,23 @@ void main() {
|
|||
expect(config.templatesDirectory.path,
|
||||
matches(RegExp(r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]templates')));
|
||||
});
|
||||
test('html skeleton file is correct', () async {
|
||||
test('html skeleton file for sample 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 no dartpad is correct', () async {
|
||||
expect(
|
||||
config.getHtmlSkeletonFile(SnippetType.application).path,
|
||||
matches(RegExp(
|
||||
r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]application.html')));
|
||||
});
|
||||
test('html skeleton file for app with dartpad is correct', () async {
|
||||
expect(
|
||||
config.getHtmlSkeletonFile(SnippetType.application, showDartPad: true).path,
|
||||
matches(RegExp(
|
||||
r'[/\\]flutter sdk[/\\]dev[/\\]snippets[/\\]config[/\\]skeletons[/\\]dartpad-application.html')));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ main() {
|
|||
{{description}}
|
||||
<pre>{{code}}</pre>
|
||||
<div>More HTML Bits</div>
|
||||
''');
|
||||
configuration.getHtmlSkeletonFile(SnippetType.application, showDartPad: true).writeAsStringSync('''
|
||||
<div>HTML Bits (DartPad-style)</div>
|
||||
<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id={{id}}"></iframe>
|
||||
<div>More HTML Bits</div>
|
||||
''');
|
||||
generator = SnippetGenerator(configuration: configuration);
|
||||
});
|
||||
|
@ -109,7 +114,11 @@ void main() {
|
|||
```
|
||||
''');
|
||||
|
||||
final String html = generator.generate(inputFile, SnippetType.sample, metadata: <String, Object>{'id': 'id'});
|
||||
final String html = generator.generate(
|
||||
inputFile,
|
||||
SnippetType.sample,
|
||||
metadata: <String, Object>{'id': 'id'},
|
||||
);
|
||||
expect(html, contains('<div>HTML Bits</div>'));
|
||||
expect(html, contains('<div>More HTML Bits</div>'));
|
||||
expect(html, contains(' print('The actual \$name.');'));
|
||||
|
@ -119,6 +128,33 @@ void main() {
|
|||
expect(html, contains('main() {'));
|
||||
});
|
||||
|
||||
test('generates dartpad snippets', () 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 String html = generator.generate(
|
||||
inputFile,
|
||||
SnippetType.application,
|
||||
showDartPad: true,
|
||||
template: 'template',
|
||||
metadata: <String, Object>{'id': 'id'},
|
||||
);
|
||||
expect(html, contains('<div>HTML Bits (DartPad-style)</div>'));
|
||||
expect(html, contains('<div>More HTML Bits</div>'));
|
||||
expect(html, contains('<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?split=60&run=true&sample_id=id"></iframe>'));
|
||||
});
|
||||
|
||||
test('generates snippet application metadata', () async {
|
||||
final File inputFile = File(path.join(tmpDir.absolute.path, 'snippet_in.txt'))
|
||||
..createSync(recursive: true)
|
||||
|
|
|
@ -89,7 +89,7 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
|
|||
/// to false. In that case a null leading widget will result in the middle/title widget
|
||||
/// stretching to start.
|
||||
///
|
||||
/// {@tool snippet --template=stateless_widget_material}
|
||||
/// {@tool dartpad --template=stateless_widget_material}
|
||||
///
|
||||
/// This sample shows an [AppBar] with two simple actions. The first action
|
||||
/// opens a [SnackBar], while the second action navigates to a new page.
|
||||
|
|
Loading…
Reference in a new issue