diff --git a/dev/snippets/README.md b/dev/snippets/README.md index a28e50db97..ce1f731f1d 100644 --- a/dev/snippets/README.md +++ b/dev/snippets/README.md @@ -113,33 +113,6 @@ demonstrate the API's functionality in a sample application, or used with the `dartpad` samples are embedded into the API docs web page and are live applications in the API documentation. -```dart -/// {@tool sample --template=stateless_widget_material} -/// This example shows how to make a simple [FloatingActionButton] in a -/// [Scaffold], with a pink [backgroundColor] and a thumbs up [Icon]. -/// -/// ```dart -/// Widget build(BuildContext context) { -/// return Scaffold( -/// appBar: AppBar( -/// title: Text('Floating Action Button Sample'), -/// ), -/// body: Center( -/// child: Text('Press the button below!') -/// ), -/// floatingActionButton: FloatingActionButton( -/// onPressed: () { -/// // Add your onPressed code here! -/// }, -/// child: Icon(Icons.thumb_up), -/// backgroundColor: Colors.pink, -/// ), -/// ); -/// } -/// ``` -/// {@end-tool} -``` - This uses the skeleton for [application](https://github.com/flutter/flutter/blob/main/dev/snippets/config/skeletons/sample.html) snippets in the Flutter repo. diff --git a/dev/snippets/bin/snippets.dart b/dev/snippets/bin/snippets.dart index 8590cadf4b..eb73a4b8ff 100644 --- a/dev/snippets/bin/snippets.dart +++ b/dev/snippets/bin/snippets.dart @@ -21,7 +21,6 @@ const String _kOutputDirectoryOption = 'output-directory'; const String _kOutputOption = 'output'; const String _kPackageOption = 'package'; const String _kSerialOption = 'serial'; -const String _kTemplateOption = 'template'; const String _kTypeOption = 'type'; class GitStatusFailed implements Exception { @@ -126,22 +125,14 @@ void main(List argList) { allowed: sampleTypes, allowedHelp: { 'dartpad': - 'Produce a code sample application complete with embedding the sample in an ' - 'application template for using in Dartpad.', + 'Produce a code sample application for using in Dartpad.', 'sample': - 'Produce a code sample application complete with embedding the sample in an ' - 'application template.', + 'Produce a code sample application.', 'snippet': - 'Produce a nicely formatted piece of sample code. Does not embed the ' - 'sample into an application template.', + 'Produce a nicely formatted piece of sample code.', }, help: 'The type of snippet to produce.', ); - // TODO(goderbauer): Remove template support, this is no longer used. - parser.addOption( - _kTemplateOption, - help: 'The name of the template to inject the code into.', - ); parser.addOption( _kOutputOption, help: 'The output name for the generated sample application. Overrides ' diff --git a/dev/snippets/lib/src/configuration.dart b/dev/snippets/lib/src/configuration.dart index 37176ce0dc..cd6e1e3faa 100644 --- a/dev/snippets/lib/src/configuration.dart +++ b/dev/snippets/lib/src/configuration.dart @@ -11,7 +11,6 @@ class SnippetConfiguration { const SnippetConfiguration({ required this.configDirectory, required this.skeletonsDirectory, - required this.templatesDirectory, this.filesystem = const LocalFileSystem(), }); @@ -25,10 +24,6 @@ class SnippetConfiguration { /// and returned to dartdoc for insertion in the output. final Directory skeletonsDirectory; - /// The directory containing the code templates that can be referenced by the - /// dartdoc. - final Directory templatesDirectory; - /// Gets the skeleton file to use for the given [SampleType] and DartPad /// preference. File getHtmlSkeletonFile(String type) { @@ -47,11 +42,6 @@ class FlutterRepoSnippetConfiguration extends SnippetConfiguration { const ['dev', 'snippets', 'config']), skeletonsDirectory: _underRoot(filesystem, flutterRoot, const ['dev', 'snippets', 'config', 'skeletons']), - templatesDirectory: _underRoot( - filesystem, - flutterRoot, - const ['dev', 'snippets', 'config', 'templates'], - ), ); final Directory flutterRoot; diff --git a/dev/snippets/lib/src/data_types.dart b/dev/snippets/lib/src/data_types.dart index fd5bac9802..4519107622 100644 --- a/dev/snippets/lib/src/data_types.dart +++ b/dev/snippets/lib/src/data_types.dart @@ -58,8 +58,8 @@ class SourceLine { /// A class containing the name and contents associated with a code block inside of a /// code sample, for named injection into a template. -class TemplateInjection { - TemplateInjection(this.name, this.contents, {this.language = ''}); +class SkeletonInjection { + SkeletonInjection(this.name, this.contents, {this.language = ''}); final String name; final List contents; final String language; @@ -137,7 +137,7 @@ abstract class CodeSample { String get element => start.element ?? ''; String output = ''; Map metadata = {}; - List parts = []; + List parts = []; SourceLine get start => input.isEmpty ? _lineProto : input.first; String get template { diff --git a/dev/snippets/lib/src/import_sorter.dart b/dev/snippets/lib/src/import_sorter.dart index ef7fa29554..ecb9f74bfb 100644 --- a/dev/snippets/lib/src/import_sorter.dart +++ b/dev/snippets/lib/src/import_sorter.dart @@ -356,7 +356,7 @@ class _DirectiveInfo implements Comparable<_DirectiveInfo> { if (priority == other.priority) { return _compareUri(uri, other.uri); } - return priority.ordinal - other.priority.ordinal; + return priority.index - other.priority.index; } @override @@ -387,23 +387,15 @@ class _DirectiveInfo implements Comparable<_DirectiveInfo> { } enum _DirectivePriority { - IMPORT_SDK('IMPORT_SDK', 0), - IMPORT_PKG('IMPORT_PKG', 1), - IMPORT_OTHER('IMPORT_OTHER', 2), - IMPORT_REL('IMPORT_REL', 3), - EXPORT_SDK('EXPORT_SDK', 4), - EXPORT_PKG('EXPORT_PKG', 5), - EXPORT_OTHER('EXPORT_OTHER', 6), - EXPORT_REL('EXPORT_REL', 7), - PART('PART', 8); - - const _DirectivePriority(this.name, this.ordinal); - - final String name; - final int ordinal; - - @override - String toString() => name; + IMPORT_SDK, + IMPORT_PKG, + IMPORT_OTHER, + IMPORT_REL, + EXPORT_SDK, + EXPORT_PKG, + EXPORT_OTHER, + EXPORT_REL, + PART } /// SourceEdit diff --git a/dev/snippets/lib/src/snippet_generator.dart b/dev/snippets/lib/src/snippet_generator.dart index f83cf7ec10..75a0c896e2 100644 --- a/dev/snippets/lib/src/snippet_generator.dart +++ b/dev/snippets/lib/src/snippet_generator.dart @@ -43,30 +43,9 @@ class SnippetGenerator { static DartFormatter formatter = DartFormatter(pageWidth: 80, fixes: StyleFix.all); - /// Gets the path to the template file requested. - File? getTemplatePath(String templateName, {Directory? templatesDir}) { - final Directory templateDir = - templatesDir ?? configuration.templatesDirectory; - final File templateFile = configuration.filesystem - .file(path.join(templateDir.path, '$templateName.tmpl')); - return templateFile.existsSync() ? templateFile : null; - } - - /// Returns an iterable over the template files available in the templates - /// directory in the configuration. - Iterable getAvailableTemplates() sync* { - final Directory templatesDir = configuration.templatesDirectory; - for (final File file in templatesDir.listSync().whereType()) { - if (file.basename.endsWith('.tmpl')) { - yield file; - } - } - } - /// Interpolates the [injections] into an HTML skeleton file. /// - /// Similar to interpolateTemplate, but we are only looking for `code-` - /// components, and we care about the order of the injections. + /// The order of the injections is important. /// /// Takes into account the [type] and doesn't substitute in the id and the app /// if not a [SnippetType.sample] snippet. @@ -77,7 +56,7 @@ class SnippetGenerator { final List codeParts = []; const HtmlEscape htmlEscape = HtmlEscape(); String? language; - for (final TemplateInjection injection in sample.parts) { + for (final SkeletonInjection injection in sample.parts) { if (!injection.name.startsWith('code')) { continue; } @@ -165,7 +144,7 @@ class SnippetGenerator { /// into valid Dart code. List _processBlocks(CodeSample sample) { final List block = sample.parts - .expand((TemplateInjection injection) => injection.contents) + .expand((SkeletonInjection injection) => injection.contents) .toList(); if (block.isEmpty) { return []; @@ -233,11 +212,11 @@ class SnippetGenerator { } /// Parses the input for the various code and description segments, and - /// returns a set of template injections in the order found. - List parseInput(CodeSample sample) { + /// returns a set of skeleton injections in the order found. + List parseInput(CodeSample sample) { bool inCodeBlock = false; final List description = []; - final List components = []; + final List components = []; String? language; final RegExp codeStartEnd = RegExp(r'^\s*```(?[-\w]+|[-\w]+ (?
[-\w]+))?\s*$'); @@ -249,12 +228,12 @@ class SnippetGenerator { if (match.namedGroup('language') != null) { language = match[1]; if (match.namedGroup('section') != null) { - components.add(TemplateInjection( + components.add(SkeletonInjection( 'code-${match.namedGroup('section')}', [], language: language!)); } else { components.add( - TemplateInjection('code', [], language: language!)); + SkeletonInjection('code', [], language: language!)); } } else { language = null; @@ -286,9 +265,9 @@ class SnippetGenerator { lastWasWhitespace = onlyWhitespace; } sample.description = descriptionLines.join('\n').trimRight(); - sample.parts = [ + sample.parts = [ if (sample is SnippetSample) - TemplateInjection('#assumptions', sample.assumptions), + SkeletonInjection('#assumptions', sample.assumptions), ...components, ]; return sample.parts; @@ -327,10 +306,6 @@ class SnippetGenerator { /// /// The optional `output` is the file to write the generated sample code to. /// - /// If `addSectionMarkers` is true, then markers will be added before and - /// after each template section in the output. This is intended to facilitate - /// editing of the sample during the authoring process. - /// /// If `includeAssumptions` is true, then the block in the "Examples can /// assume:" block will also be included in the output. /// @@ -341,58 +316,16 @@ class SnippetGenerator { String? copyright, String? description, bool formatOutput = true, - bool addSectionMarkers = false, bool includeAssumptions = false, }) { sample.metadata['copyright'] ??= copyright; - final List snippetData = parseInput(sample); + final List snippetData = parseInput(sample); sample.description = description ?? sample.description; sample.metadata['description'] = _getDescription(sample); - switch (sample.runtimeType) { + switch (sample) { case DartpadSample _: case ApplicationSample _: - String app; - if (sample.sourceFile == null) { - final String templateName = sample.template; - if (templateName.isEmpty) { - io.stderr - .writeln('Non-linked samples must have a --template argument.'); - io.exit(1); - } - final Directory templatesDir = configuration.templatesDirectory; - File? templateFile; - templateFile = - getTemplatePath(templateName, templatesDir: templatesDir); - if (templateFile == null) { - io.stderr.writeln( - 'The template $templateName was not found in the templates ' - 'directory ${templatesDir.path}'); - io.exit(1); - } - final String templateContents = _loadFileAsUtf8(templateFile); - final String templateRelativePath = - templateFile.absolute.path.contains(flutterRoot.absolute.path) - ? path.relative(templateFile.absolute.path, - from: flutterRoot.absolute.path) - : templateFile.absolute.path; - final String templateHeader = ''' -// Template: $templateRelativePath -// -// Comment lines marked with "▼▼▼" and "▲▲▲" are used for authoring -// of samples, and may be ignored if you are just exploring the sample. -'''; - app = interpolateTemplate( - snippetData, - addSectionMarkers - ? '$templateHeader\n$templateContents' - : templateContents, - sample.metadata, - addSectionMarkers: addSectionMarkers, - addCopyright: copyright != null, - ); - } else { - app = sample.sourceFileContents; - } + final String app = sample.sourceFileContents; sample.output = app; if (formatOutput) { final DartFormatter formatter = @@ -421,13 +354,14 @@ class SnippetGenerator { metadataFile.writeAsStringSync(jsonEncoder.convert(metadata)); } case SnippetSample _: - if (sample is SnippetSample) { String app; if (sample.sourceFile == null) { String templateContents; if (includeAssumptions) { templateContents = - '${headers.map((SourceLine line) => line.text).join('\n')}\n{{#assumptions}}\n{{description}}\n{{code}}'; + '${headers.map((SourceLine line) { + return line.text; + }).join('\n')}\n{{#assumptions}}\n{{description}}\n{{code}}'; } else { templateContents = '{{description}}\n{{code}}'; } @@ -435,14 +369,12 @@ class SnippetGenerator { snippetData, templateContents, sample.metadata, - addSectionMarkers: addSectionMarkers, addCopyright: copyright != null, ); } else { app = sample.inputAsString; } sample.output = app; - } } return sample.output; } diff --git a/dev/snippets/lib/src/snippet_parser.dart b/dev/snippets/lib/src/snippet_parser.dart index 9af60b4834..9678d6e0ca 100644 --- a/dev/snippets/lib/src/snippet_parser.dart +++ b/dev/snippets/lib/src/snippet_parser.dart @@ -176,7 +176,7 @@ class SnippetDartdocParser { } parseComment(element); for (final CodeSample sample in element.samples) { - switch (sample.runtimeType) { + switch (sample) { case DartpadSample _: dartpadCount++; case ApplicationSample _: diff --git a/dev/snippets/lib/src/util.dart b/dev/snippets/lib/src/util.dart index c090795e69..e0c6f5cbc1 100644 --- a/dev/snippets/lib/src/util.dart +++ b/dev/snippets/lib/src/util.dart @@ -140,28 +140,12 @@ class FlutterInformation { } } -/// Returns a marker with section arrows surrounding the given string. -/// -/// Specifying `start` as false returns an ending marker instead of a starting -/// marker. -String sectionArrows(String name, {bool start = true}) { - const int markerArrows = 8; - final String arrows = - (start ? '\u25bc' /* ▼ */ : '\u25b2' /* ▲ */) * markerArrows; - final String marker = - '//* $arrows $name $arrows (do not modify or remove section marker)'; - return '${start ? '\n//*${'*' * marker.length}\n' : '\n'}' - '$marker' - '${!start ? '\n//*${'*' * marker.length}\n' : '\n'}'; -} - /// Injects the [injections] into the [template], while turning the /// "description" injection into a comment. String interpolateTemplate( - List injections, + List injections, String template, Map metadata, { - bool addSectionMarkers = false, bool addCopyright = false, }) { String wrapSectionMarker(Iterable contents, {required String name}) { @@ -170,13 +154,8 @@ String interpolateTemplate( return ''; } // We don't wrap some sections, because otherwise they generate invalid files. - const Set skippedSections = {'element', 'copyright'}; - final bool addMarkers = - addSectionMarkers && !skippedSections.contains(name); final String result = [ - if (addMarkers) sectionArrows(name), ...contents, - if (addMarkers) sectionArrows(name, start: false), ].join('\n'); final RegExp wrappingNewlines = RegExp(r'^\n*(.*)\n*$', dotAll: true); return result.replaceAllMapped( @@ -187,7 +166,7 @@ String interpolateTemplate( .replaceAllMapped(RegExp(r'{{([^}]+)}}'), (Match match) { final String name = match[1]!; final int componentIndex = injections - .indexWhere((TemplateInjection injection) => injection.name == name); + .indexWhere((SkeletonInjection injection) => injection.name == name); if (metadata[name] != null && componentIndex == -1) { // If the match isn't found in the injections, then just return the // metadata entry. diff --git a/dev/snippets/test/configuration_test.dart b/dev/snippets/test/configuration_test.dart index 568a491fb7..4659b6b1a1 100644 --- a/dev/snippets/test/configuration_test.dart +++ b/dev/snippets/test/configuration_test.dart @@ -27,12 +27,6 @@ void main() { 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('snippet').path, diff --git a/dev/snippets/test/snippet_parser_test.dart b/dev/snippets/test/snippet_parser_test.dart index b1de8574f4..3de2fbe5db 100644 --- a/dev/snippets/test/snippet_parser_test.dart +++ b/dev/snippets/test/snippet_parser_test.dart @@ -37,7 +37,6 @@ void main() { late FlutterRepoSnippetConfiguration configuration; late SnippetGenerator generator; late Directory tmpDir; - late File template; late Directory flutterRoot; void writeSkeleton(String type) { @@ -69,25 +68,13 @@ void main() { .directory(path.join(tmpDir.absolute.path, 'flutter')); configuration = FlutterRepoSnippetConfiguration( flutterRoot: flutterRoot, filesystem: memoryFileSystem); - configuration.templatesDirectory.createSync(recursive: true); configuration.skeletonsDirectory.createSync(recursive: true); - template = memoryFileSystem.file( - path.join(configuration.templatesDirectory.path, 'template.tmpl')); - template.writeAsStringSync(''' -// Flutter code sample for {{element}} - -{{description}} - -{{code-my-preamble}} - -{{code}} -'''); ['dartpad', 'sample', 'snippet'].forEach(writeSkeleton); FlutterInformation.instance = FakeFlutterInformation(flutterRoot); generator = SnippetGenerator( configuration: configuration, filesystem: memoryFileSystem, - flutterRoot: configuration.templatesDirectory.parent); + flutterRoot: configuration.skeletonsDirectory.parent); }); test('parses from comments', () async { @@ -124,35 +111,6 @@ void main() { } expect(sampleCount, equals(8)); }); - test('parses dartpad samples from comments', () async { - final File inputFile = - _createDartpadSourceFile(tmpDir, memoryFileSystem, flutterRoot); - final Iterable elements = getFileElements(inputFile, - resourceProvider: FileSystemResourceProvider(memoryFileSystem)); - expect(elements, isNotEmpty); - final SnippetDartdocParser sampleParser = - SnippetDartdocParser(memoryFileSystem); - sampleParser.parseFromComments(elements); - expect(elements.length, equals(1)); - int sampleCount = 0; - for (final SourceElement element in elements) { - expect(element.samples.length, greaterThanOrEqualTo(1)); - sampleCount += element.samples.length; - final String code = generator.generateCode(element.samples.first); - expect(code, contains('// Description')); - expect( - code, - contains(RegExp('^void ${element.name}Sample\\(\\) \\{.*\$', - multiLine: true))); - final String html = generator.generateHtml(element.samples.first); - expect( - html, - contains(RegExp( - '''^