diff --git a/dev/snippets/bin/snippets.dart b/dev/snippets/bin/snippets.dart index efc1e77f99..fd06498951 100644 --- a/dev/snippets/bin/snippets.dart +++ b/dev/snippets/bin/snippets.dart @@ -13,7 +13,6 @@ import 'package:process/process.dart'; import 'package:snippets/snippets.dart'; const String _kElementOption = 'element'; -const String _kFormatOutputOption = 'format-output'; const String _kHelpOption = 'help'; const String _kInputOption = 'input'; const String _kLibraryOption = 'library'; @@ -165,11 +164,6 @@ void main(List argList) { defaultsTo: environment['INVOCATION_INDEX'], help: 'A unique serial number for this snippet tool invocation.', ); - parser.addFlag( - _kFormatOutputOption, - defaultsTo: true, - help: 'Applies the Dart formatter to the published/extracted sample code.', - ); parser.addFlag( _kHelpOption, negatable: false, @@ -201,7 +195,6 @@ void main(List argList) { return; } - final bool formatOutput = args[_kFormatOutputOption]! as bool; final String packageName = args[_kPackageOption] as String? ?? ''; final String libraryName = args[_kLibraryOption] as String? ?? ''; final String elementName = args[_kElementOption] as String? ?? ''; @@ -268,7 +261,7 @@ void main(List argList) { for (final CodeSample sample in element.samples) { sample.metadata.addAll(metadata); - snippetGenerator.generateCode(sample, output: output, formatOutput: formatOutput); + snippetGenerator.generateCode(sample, output: output); print(snippetGenerator.generateHtml(sample)); } diff --git a/dev/snippets/lib/snippets.dart b/dev/snippets/lib/snippets.dart index 116ae7970b..397ce0f56f 100644 --- a/dev/snippets/lib/snippets.dart +++ b/dev/snippets/lib/snippets.dart @@ -5,7 +5,6 @@ export 'src/analysis.dart'; export 'src/configuration.dart'; export 'src/data_types.dart'; -export 'src/import_sorter.dart'; export 'src/snippet_generator.dart'; export 'src/snippet_parser.dart'; export 'src/util.dart'; diff --git a/dev/snippets/lib/src/import_sorter.dart b/dev/snippets/lib/src/import_sorter.dart deleted file mode 100644 index 8db741dac2..0000000000 --- a/dev/snippets/lib/src/import_sorter.dart +++ /dev/null @@ -1,432 +0,0 @@ -// 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:math'; - -import 'package:analyzer/dart/analysis/features.dart'; -import 'package:analyzer/dart/analysis/results.dart'; -import 'package:analyzer/dart/analysis/utilities.dart'; -import 'package:analyzer/dart/ast/ast.dart'; -import 'package:analyzer/dart/ast/token.dart'; -import 'package:analyzer/error/error.dart'; -import 'package:analyzer/source/line_info.dart'; -import 'package:meta/meta.dart'; - -import 'util.dart'; - -/// Read the given source code, and return the new contents after sorting the -/// imports. -String sortImports(String contents) { - final ParseStringResult parseResult = parseString( - content: contents, - featureSet: FeatureSet.fromEnableFlags2( - sdkLanguageVersion: FlutterInformation.instance.getDartSdkVersion(), - flags: [], - ), - ); - final List errors = []; - final _ImportOrganizer organizer = _ImportOrganizer(contents, parseResult.unit, errors); - final List<_SourceEdit> edits = organizer.organize(); - // Sort edits in reverse order - edits.sort((_SourceEdit a, _SourceEdit b) { - return b.offset.compareTo(a.offset); - }); - // Apply edits - for (final _SourceEdit edit in edits) { - contents = contents.replaceRange(edit.offset, edit.end, edit.replacement); - } - return contents; -} - -/// Organizer of imports (and other directives) in the [unit]. -// Adapted from the analysis_server package. -// This code is largely copied from: -// https://github.com/dart-lang/sdk/blob/c7405b9d86b4b47cf7610667491f1db72723b0dd/pkg/analysis_server/lib/src/services/correction/organize_imports.dart#L15 -// TODO(gspencergoog): If ImportOrganizer ever becomes part of the public API, -// this class should probably be replaced. -// https://github.com/flutter/flutter/issues/86197 -class _ImportOrganizer { - _ImportOrganizer(this.initialCode, this.unit, this.errors) : code = initialCode { - endOfLine = getEOL(code); - hasUnresolvedIdentifierError = errors.any((AnalysisError error) { - return error.errorCode.isUnresolvedIdentifier; - }); - } - - final String initialCode; - - final CompilationUnit unit; - - final List errors; - - String code; - - String endOfLine = '\n'; - - bool hasUnresolvedIdentifierError = false; - - /// Returns the number of characters common to the end of [a] and [b]. - int findCommonSuffix(String a, String b) { - final int aLength = a.length; - final int bLength = b.length; - final int n = min(aLength, bLength); - for (int i = 1; i <= n; i++) { - if (a.codeUnitAt(aLength - i) != b.codeUnitAt(bLength - i)) { - return i - 1; - } - } - return n; - } - - /// Return the [_SourceEdit]s that organize imports in the [unit]. - List<_SourceEdit> organize() { - _organizeDirectives(); - // prepare edits - final List<_SourceEdit> edits = <_SourceEdit>[]; - if (code != initialCode) { - final int suffixLength = findCommonSuffix(initialCode, code); - final _SourceEdit edit = _SourceEdit( - 0, - initialCode.length - suffixLength, - code.substring(0, code.length - suffixLength), - ); - edits.add(edit); - } - return edits; - } - - /// Organize all [Directive]s. - void _organizeDirectives() { - final LineInfo lineInfo = unit.lineInfo; - bool hasLibraryDirective = false; - final List<_DirectiveInfo> directives = <_DirectiveInfo>[]; - for (final Directive directive in unit.directives) { - if (directive is LibraryDirective) { - hasLibraryDirective = true; - } - if (directive is UriBasedDirective) { - final _DirectivePriority? priority = getDirectivePriority(directive); - if (priority != null) { - int offset = directive.offset; - int end = directive.end; - - final Token? leadingComment = getLeadingComment(unit, directive, lineInfo); - final Token? trailingComment = getTrailingComment(unit, directive, lineInfo, end); - - String? leadingCommentText; - if (leadingComment != null) { - leadingCommentText = code.substring(leadingComment.offset, directive.offset); - offset = leadingComment.offset; - } - String? trailingCommentText; - if (trailingComment != null) { - trailingCommentText = code.substring(directive.end, trailingComment.end); - end = trailingComment.end; - } - String? documentationText; - final Comment? documentationComment = directive.documentationComment; - if (documentationComment != null) { - documentationText = code.substring( - documentationComment.offset, - documentationComment.end, - ); - } - String? annotationText; - final Token? beginToken = directive.metadata.beginToken; - final Token? endToken = directive.metadata.endToken; - if (beginToken != null && endToken != null) { - annotationText = code.substring(beginToken.offset, endToken.end); - } - final String text = code.substring( - directive.firstTokenAfterCommentAndMetadata.offset, - directive.end, - ); - final String uriContent = directive.uri.stringValue ?? ''; - directives.add( - _DirectiveInfo( - directive, - priority, - leadingCommentText, - documentationText, - annotationText, - uriContent, - trailingCommentText, - offset, - end, - text, - ), - ); - } - } - } - // nothing to do - if (directives.isEmpty) { - return; - } - final int firstDirectiveOffset = directives.first.offset; - final int lastDirectiveEnd = directives.last.end; - - // Without a library directive, the library comment is the comment of the - // first directive. - _DirectiveInfo? libraryDocumentationDirective; - if (!hasLibraryDirective && directives.isNotEmpty) { - libraryDocumentationDirective = directives.first; - } - - // sort - directives.sort(); - // append directives with grouping - String directivesCode; - { - final StringBuffer sb = StringBuffer(); - if (libraryDocumentationDirective != null && - libraryDocumentationDirective.documentationText != null) { - sb.write(libraryDocumentationDirective.documentationText); - sb.write(endOfLine); - } - _DirectivePriority currentPriority = directives.first.priority; - for (final _DirectiveInfo directiveInfo in directives) { - if (currentPriority != directiveInfo.priority) { - sb.write(endOfLine); - currentPriority = directiveInfo.priority; - } - if (directiveInfo.leadingCommentText != null) { - sb.write(directiveInfo.leadingCommentText); - } - if (directiveInfo != libraryDocumentationDirective && - directiveInfo.documentationText != null) { - sb.write(directiveInfo.documentationText); - sb.write(endOfLine); - } - if (directiveInfo.annotationText != null) { - sb.write(directiveInfo.annotationText); - sb.write(endOfLine); - } - sb.write(directiveInfo.text); - if (directiveInfo.trailingCommentText != null) { - sb.write(directiveInfo.trailingCommentText); - } - sb.write(endOfLine); - } - directivesCode = sb.toString(); - directivesCode = directivesCode.trimRight(); - } - // prepare code - final String beforeDirectives = code.substring(0, firstDirectiveOffset); - final String afterDirectives = code.substring(lastDirectiveEnd); - code = beforeDirectives + directivesCode + afterDirectives; - } - - static _DirectivePriority? getDirectivePriority(UriBasedDirective directive) { - final String uriContent = directive.uri.stringValue ?? ''; - if (directive is ImportDirective) { - if (uriContent.startsWith('dart:')) { - return _DirectivePriority.IMPORT_SDK; - } else if (uriContent.startsWith('package:')) { - return _DirectivePriority.IMPORT_PKG; - } else if (uriContent.contains('://')) { - return _DirectivePriority.IMPORT_OTHER; - } else { - return _DirectivePriority.IMPORT_REL; - } - } - if (directive is ExportDirective) { - if (uriContent.startsWith('dart:')) { - return _DirectivePriority.EXPORT_SDK; - } else if (uriContent.startsWith('package:')) { - return _DirectivePriority.EXPORT_PKG; - } else if (uriContent.contains('://')) { - return _DirectivePriority.EXPORT_OTHER; - } else { - return _DirectivePriority.EXPORT_REL; - } - } - if (directive is PartDirective) { - return _DirectivePriority.PART; - } - return null; - } - - /// Return the EOL to use for [code]. - static String getEOL(String code) { - if (code.contains('\r\n')) { - return '\r\n'; - } else { - return '\n'; - } - } - - /// Gets the first comment token considered to be the leading comment for this - /// directive. - /// - /// Leading comments for the first directive in a file are considered library - /// comments and not returned unless they contain blank lines, in which case - /// only the last part of the comment will be returned. - static Token? getLeadingComment( - CompilationUnit unit, - UriBasedDirective directive, - LineInfo lineInfo, - ) { - if (directive.beginToken.precedingComments == null) { - return null; - } - - Token? firstComment = directive.beginToken.precedingComments; - Token? comment = firstComment; - Token? nextComment = comment?.next; - // Don't connect comments that have a blank line between them - while (comment != null && nextComment != null) { - final int currentLine = lineInfo.getLocation(comment.offset).lineNumber; - final int nextLine = lineInfo.getLocation(nextComment.offset).lineNumber; - if (nextLine - currentLine > 1) { - firstComment = nextComment; - } - comment = nextComment; - nextComment = comment.next; - } - - // Check if the comment is the first comment in the document - if (firstComment != unit.beginToken.precedingComments) { - final int previousDirectiveLine = - lineInfo.getLocation(directive.beginToken.previous!.end).lineNumber; - - // Skip over any comments on the same line as the previous directive - // as they will be attached to the end of it. - Token? comment = firstComment; - while (comment != null && - previousDirectiveLine == lineInfo.getLocation(comment.offset).lineNumber) { - comment = comment.next; - } - return comment; - } - return null; - } - - /// Gets the last comment token considered to be the trailing comment for this - /// directive. - /// - /// To be considered a trailing comment, the comment must be on the same line - /// as the directive. - static Token? getTrailingComment( - CompilationUnit unit, - UriBasedDirective directive, - LineInfo lineInfo, - int end, - ) { - final int line = lineInfo.getLocation(end).lineNumber; - Token? comment = directive.endToken.next!.precedingComments; - while (comment != null) { - if (lineInfo.getLocation(comment.offset).lineNumber == line) { - return comment; - } - comment = comment.next; - } - return null; - } -} - -class _DirectiveInfo implements Comparable<_DirectiveInfo> { - _DirectiveInfo( - this.directive, - this.priority, - this.leadingCommentText, - this.documentationText, - this.annotationText, - this.uri, - this.trailingCommentText, - this.offset, - this.end, - this.text, - ); - - final UriBasedDirective directive; - final _DirectivePriority priority; - final String? leadingCommentText; - final String? documentationText; - final String? annotationText; - final String uri; - final String? trailingCommentText; - - /// The offset of the first token, usually the keyword but may include leading comments. - final int offset; - - /// The offset after the last token, including the end-of-line comment. - final int end; - - /// The text excluding comments, documentation and annotations. - final String text; - - @override - int compareTo(_DirectiveInfo other) { - if (priority == other.priority) { - return _compareUri(uri, other.uri); - } - return priority.index - other.priority.index; - } - - @override - String toString() => '(priority=$priority; text=$text)'; - - static int _compareUri(String a, String b) { - final List aList = _splitUri(a); - final List bList = _splitUri(b); - int result; - if ((result = aList[0].compareTo(bList[0])) != 0) { - return result; - } - if ((result = aList[1].compareTo(bList[1])) != 0) { - return result; - } - return 0; - } - - /// Split the given [uri] like `package:some.name/and/path.dart` into a list - /// like `[package:some.name, and/path.dart]`. - static List _splitUri(String uri) { - final int index = uri.indexOf('/'); - if (index == -1) { - return [uri, '']; - } - return [uri.substring(0, index), uri.substring(index + 1)]; - } -} - -enum _DirectivePriority { - IMPORT_SDK, - IMPORT_PKG, - IMPORT_OTHER, - IMPORT_REL, - EXPORT_SDK, - EXPORT_PKG, - EXPORT_OTHER, - EXPORT_REL, - PART, -} - -/// SourceEdit -/// -/// { -/// "offset": int -/// "length": int -/// "replacement": String -/// "id": optional String -/// } -/// -/// Clients may not extend, implement or mix-in this class. -@immutable -class _SourceEdit { - const _SourceEdit(this.offset, this.length, this.replacement); - - /// The offset of the region to be modified. - final int offset; - - /// The length of the region to be modified. - final int length; - - /// The end of the region to be modified. - int get end => offset + length; - - /// The code that is to replace the specified region in the original code. - final String replacement; -} diff --git a/dev/snippets/lib/src/snippet_generator.dart b/dev/snippets/lib/src/snippet_generator.dart index 4aba150ac2..1f7e647af1 100644 --- a/dev/snippets/lib/src/snippet_generator.dart +++ b/dev/snippets/lib/src/snippet_generator.dart @@ -3,16 +3,13 @@ // found in the LICENSE file. import 'dart:convert'; -import 'dart:io' as io; -import 'package:dart_style/dart_style.dart'; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:path/path.dart' as path; import 'configuration.dart'; import 'data_types.dart'; -import 'import_sorter.dart'; import 'util.dart'; /// Generates the snippet HTML, as well as saving the output snippet main to @@ -38,10 +35,6 @@ class SnippetGenerator { 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); - /// Interpolates the [injections] into an HTML skeleton file. /// /// The order of the injections is important. @@ -304,7 +297,6 @@ class SnippetGenerator { File? output, String? copyright, String? description, - bool formatOutput = true, bool includeAssumptions = false, }) { sample.metadata['copyright'] ??= copyright; @@ -316,16 +308,6 @@ class SnippetGenerator { case ApplicationSample _: final String app = sample.sourceFileContents; sample.output = app; - if (formatOutput) { - final DartFormatter formatter = DartFormatter(pageWidth: 80, fixes: StyleFix.all); - try { - sample.output = formatter.format(sample.output); - } on FormatterException catch (exception) { - io.stderr.write('Code to format:\n${_addLineNumbers(sample.output)}\n'); - errorExit('Unable to format sample code: $exception'); - } - sample.output = sortImports(sample.output); - } if (output != null) { output.writeAsStringSync(sample.output); @@ -371,16 +353,6 @@ class SnippetGenerator { return sample.output; } - String _addLineNumbers(String code) { - final StringBuffer buffer = StringBuffer(); - int count = 0; - for (final String line in code.split('\n')) { - count++; - buffer.writeln('${count.toString().padLeft(5)}: $line'); - } - return buffer.toString(); - } - /// Computes the headers needed for each snippet file. /// /// Not used for "sample" and "dartpad" samples, which use their own template. diff --git a/dev/snippets/pubspec.yaml b/dev/snippets/pubspec.yaml index 4bcb08adb9..750a704196 100644 --- a/dev/snippets/pubspec.yaml +++ b/dev/snippets/pubspec.yaml @@ -7,7 +7,6 @@ environment: dependencies: analyzer: 6.11.0 args: 2.6.0 - dart_style: 2.3.7 file: 7.0.1 meta: 1.16.0 path: 1.9.1 @@ -63,4 +62,4 @@ dev_dependencies: executables: snippets: -# PUBSPEC CHECKSUM: a1c2 +# PUBSPEC CHECKSUM: 5630 diff --git a/dev/snippets/test/import_sorter_test.dart b/dev/snippets/test/import_sorter_test.dart deleted file mode 100644 index aa2afa8eb7..0000000000 --- a/dev/snippets/test/import_sorter_test.dart +++ /dev/null @@ -1,109 +0,0 @@ -// 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 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:path/path.dart' as path; -import 'package:pub_semver/pub_semver.dart'; -import 'package:snippets/snippets.dart'; -import 'package:test/test.dart' hide TypeMatcher, isInstanceOf; - -class FakeFlutterInformation extends FlutterInformation { - FakeFlutterInformation(this.flutterRoot); - - final Directory flutterRoot; - - @override - Map getFlutterInformation() { - return { - 'flutterRoot': flutterRoot, - 'frameworkVersion': Version(2, 10, 0), - 'dartSdkVersion': Version(2, 12, 1), - }; - } -} - -void main() { - late MemoryFileSystem memoryFileSystem = MemoryFileSystem(); - late Directory tmpDir; - - setUp(() { - // Create a new filesystem. - memoryFileSystem = MemoryFileSystem(); - tmpDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_snippets_test.'); - final Directory flutterRoot = memoryFileSystem.directory( - path.join(tmpDir.absolute.path, 'flutter'), - ); - FlutterInformation.instance = FakeFlutterInformation(flutterRoot); - }); - - test('Sorting packages works', () async { - final String result = sortImports(''' -// Unit comment - -// third import -import 'packages:gamma/gamma.dart'; // third - -// second import -import 'packages:beta/beta.dart'; // second - -// first import -import 'packages:alpha/alpha.dart'; // first - -void main() {} -'''); - expect( - result, - equals(''' -// Unit comment - -// first import -import 'packages:alpha/alpha.dart'; // first -// second import -import 'packages:beta/beta.dart'; // second -// third import -import 'packages:gamma/gamma.dart'; // third - -void main() {} -'''), - ); - }); - test('Sorting dart and packages works', () async { - final String result = sortImports(''' -// Unit comment - -// third import -import 'packages:gamma/gamma.dart'; // third - -// second import -import 'packages:beta/beta.dart'; // second - -// first import -import 'packages:alpha/alpha.dart'; // first - -// first dart -import 'dart:async'; - -void main() {} -'''); - expect( - result, - equals(''' -// Unit comment - -// first dart -import 'dart:async'; - -// first import -import 'packages:alpha/alpha.dart'; // first -// second import -import 'packages:beta/beta.dart'; // second -// third import -import 'packages:gamma/gamma.dart'; // third - -void main() {} -'''), - ); - }); -} diff --git a/dev/snippets/test/snippet_parser_test.dart b/dev/snippets/test/snippet_parser_test.dart index 589488c0c1..2646168de2 100644 --- a/dev/snippets/test/snippet_parser_test.dart +++ b/dev/snippets/test/snippet_parser_test.dart @@ -139,7 +139,7 @@ void main() { for (final SourceElement element in elements) { expect(element.samples.length, greaterThanOrEqualTo(1)); sampleCount += element.samples.length; - final String code = generator.generateCode(element.samples.first, formatOutput: false); + final String code = generator.generateCode(element.samples.first); expect(code, contains('// Description')); expect( code,