diff --git a/CHANGELOG.md b/CHANGELOG.md index 88fa6cb5..d8e3d177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.2-wip + +* Support dot shorthand syntax. +* Enable language version 3.10. + ## 3.1.1 * Update to latest analyzer and enable language version 3.9. diff --git a/lib/src/cli/formatter_options.dart b/lib/src/cli/formatter_options.dart index c7f45a8f..648ec8c4 100644 --- a/lib/src/cli/formatter_options.dart +++ b/lib/src/cli/formatter_options.dart @@ -13,7 +13,7 @@ import 'show.dart'; import 'summary.dart'; // Note: The following line of code is modified by tool/grind.dart. -const dartStyleVersion = '3.1.1'; +const dartStyleVersion = '3.1.2-wip'; /// Global options parsed from the command line that affect how the formatter /// produces and uses its outputs. diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart index eb4cb713..4ddd74f1 100644 --- a/lib/src/dart_formatter.dart +++ b/lib/src/dart_formatter.dart @@ -7,6 +7,7 @@ import 'package:analyzer/dart/analysis/features.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/diagnostic/diagnostic.dart'; import 'package:analyzer/error/error.dart'; // ignore: implementation_imports import 'package:analyzer/src/dart/scanner/scanner.dart'; @@ -34,7 +35,7 @@ final RegExp _widthCommentPattern = RegExp(r'^// dart format width=(\d+)$'); final class DartFormatter { /// The latest Dart language version that can be parsed and formatted by this /// version of the formatter. - static final latestLanguageVersion = Version(3, 9, 0); + static final latestLanguageVersion = Version(3, 10, 0); /// The latest Dart language version that will be formatted using the older /// "short" style. @@ -176,7 +177,7 @@ final class DartFormatter { // Throw if there are syntactic errors. var syntacticErrors = parseResult.errors.where((error) { - return error.errorCode.type == ErrorType.SYNTACTIC_ERROR; + return error.diagnosticCode.type == DiagnosticType.SYNTACTIC_ERROR; }).toList(); if (syntacticErrors.isNotEmpty) { throw FormatterException(syntacticErrors); @@ -194,11 +195,11 @@ final class DartFormatter { var token = node.endToken.next!; if (token.type != TokenType.CLOSE_CURLY_BRACKET) { var stringSource = StringSource(text, source.uri); - var error = AnalysisError.tmp( + var error = Diagnostic.tmp( source: stringSource, offset: token.offset - inputOffset, length: math.max(token.length, 1), - errorCode: ParserErrorCode.UNEXPECTED_TOKEN, + diagnosticCode: ParserErrorCode.UNEXPECTED_TOKEN, arguments: [token.lexeme], ); throw FormatterException([error]); diff --git a/lib/src/exceptions.dart b/lib/src/exceptions.dart index 58213080..7c859efb 100644 --- a/lib/src/exceptions.dart +++ b/lib/src/exceptions.dart @@ -2,14 +2,14 @@ // for details. 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:analyzer/error/error.dart'; +import 'package:analyzer/diagnostic/diagnostic.dart'; import 'package:source_span/source_span.dart'; /// Thrown when one or more errors occurs while parsing the code to be /// formatted. final class FormatterException implements Exception { - /// The [AnalysisError]s that occurred. - final List errors; + /// The [Diagnostic]s that occurred. + final List errors; /// Creates a new FormatterException with an optional error [message]. const FormatterException(this.errors); diff --git a/lib/src/front_end/ast_node_visitor.dart b/lib/src/front_end/ast_node_visitor.dart index 6f0d5ba8..d33c0c72 100644 --- a/lib/src/front_end/ast_node_visitor.dart +++ b/lib/src/front_end/ast_node_visitor.dart @@ -531,7 +531,7 @@ final class AstNodeVisitor extends ThrowingAstVisitor with PieceFactory { // The name of the type being constructed. var type = node.type; - pieces.token(type.name2); + pieces.token(type.name); pieces.visit(type.typeArguments); pieces.token(type.question); @@ -589,6 +589,31 @@ final class AstNodeVisitor extends ThrowingAstVisitor with PieceFactory { pieces.token(node.semicolon); } + @override + void visitDotShorthandConstructorInvocation( + DotShorthandConstructorInvocation node, + ) { + pieces.modifier(node.constKeyword); + pieces.token(node.period); + pieces.visit(node.constructorName); + pieces.visit(node.typeArguments); + pieces.visit(node.argumentList); + } + + @override + void visitDotShorthandInvocation(DotShorthandInvocation node) { + pieces.token(node.period); + pieces.visit(node.memberName); + pieces.visit(node.typeArguments); + pieces.visit(node.argumentList); + } + + @override + void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) { + pieces.token(node.period); + pieces.visit(node.propertyName); + } + @override void visitDottedName(DottedName node) { writeDotted(node.components); @@ -1229,7 +1254,7 @@ final class AstNodeVisitor extends ThrowingAstVisitor with PieceFactory { // The type being constructed. var type = constructor.type; - pieces.token(type.name2); + pieces.token(type.name); pieces.visit(type.typeArguments); // If this is a named constructor call, the name. @@ -1334,7 +1359,7 @@ final class AstNodeVisitor extends ThrowingAstVisitor with PieceFactory { void visitLibraryDirective(LibraryDirective node) { pieces.withMetadata(node.metadata, () { pieces.token(node.libraryKeyword); - pieces.visit(node.name2, spaceBefore: true); + pieces.visit(node.name, spaceBefore: true); pieces.token(node.semicolon); }); } @@ -1536,7 +1561,7 @@ final class AstNodeVisitor extends ThrowingAstVisitor with PieceFactory { void visitNamedType(NamedType node) { pieces.token(node.importPrefix?.name); pieces.token(node.importPrefix?.period); - pieces.token(node.name2); + pieces.token(node.name); pieces.visit(node.typeArguments); pieces.token(node.question); } diff --git a/lib/src/short/source_visitor.dart b/lib/src/short/source_visitor.dart index a235bb2e..3124d186 100644 --- a/lib/src/short/source_visitor.dart +++ b/lib/src/short/source_visitor.dart @@ -1970,9 +1970,7 @@ final class SourceVisitor extends ThrowingAstVisitor { _visitDirectiveMetadata(node); _simpleStatement(node, () { token(node.libraryKeyword); - if (node.name2 != null) { - visit(node.name2, before: space); - } + if (node.name case var name?) visit(name, before: space); }); } @@ -2184,10 +2182,10 @@ final class SourceVisitor extends ThrowingAstVisitor { token(importPrefix.name); soloZeroSplit(); token(importPrefix.period); - token(node.name2); + token(node.name); builder.endSpan(); } else { - token(node.name2); + token(node.name); } visit(node.typeArguments); diff --git a/pubspec.yaml b/pubspec.yaml index 2dbdc1d5..07c31c2f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dart_style # Note: See tool/grind.dart for how to bump the version. -version: 3.1.1 +version: 3.1.2-wip description: >- Opinionated, automatic Dart source code formatter. Provides an API and a CLI tool. @@ -9,7 +9,7 @@ environment: sdk: ^3.7.0 dependencies: - analyzer: ^7.5.2 + analyzer: ^8.0.0 args: ">=1.0.0 <3.0.0" collection: "^1.17.0" package_config: ^2.1.0 diff --git a/test/tall/invocation/dot_shorthand.stmt b/test/tall/invocation/dot_shorthand.stmt new file mode 100644 index 00000000..0bafee2a --- /dev/null +++ b/test/tall/invocation/dot_shorthand.stmt @@ -0,0 +1,77 @@ +40 columns | +(experiment dot-shorthands) +>>> Getter. +variable = . getter; +<<< 3.9 +variable = .getter; +>>> Method call with unsplit arguments. +variable = .method(1,x:2,3,y:4); +<<< 3.9 +variable = .method(1, x: 2, 3, y: 4); +>>> Method call with split arguments. +variable = .method(one, x: two, three, y: four); +<<< 3.9 +variable = .method( + one, + x: two, + three, + y: four, +); +>>> Generic method call. +variable = . method < int , String > ( ) ; +<<< 3.9 +variable = .method(); +>>> Constructor. +variable = .new(1); +<<< 3.9 +variable = .new(1); +>>> Const constructor. +variable = const . new ( ); +<<< 3.9 +variable = const .new(); +>>> Const named constructor. +variable = const . named ( ); +<<< 3.9 +variable = const .named(); +>>> Unsplit selector chain. +v = . property . method() . x . another(); +<<< 3.9 +v = .property.method().x.another(); +>>> Split selector chain on shorthand getter. +variable = .shorthand.method().another().third(); +<<< 3.9 +variable = .shorthand + .method() + .another() + .third(); +>>> Split selector chain on shorthand method. +variable = .shorthand().method().getter.another().third(); +<<< 3.9 +variable = .shorthand() + .method() + .getter + .another() + .third(); +>>> Split in shorthand method call argument list. +context(.shorthand(argument, anotherArgument, thirdArgument) +.chain().another().third().fourthOne()); +<<< 3.9 +context( + .shorthand( + argument, + anotherArgument, + thirdArgument, + ) + .chain() + .another() + .third() + .fourthOne(), +); +>>> Nested call. +.method(.getter,.method(.new(.new())),const.ctor()); +<<< +.method( + .getter, + .method(.new(.new())), + const .ctor(), +); diff --git a/test/tall/invocation/dot_shorthand_comment.stmt b/test/tall/invocation/dot_shorthand_comment.stmt new file mode 100644 index 00000000..d5cde8c4 --- /dev/null +++ b/test/tall/invocation/dot_shorthand_comment.stmt @@ -0,0 +1,26 @@ +40 columns | +(experiment dot-shorthands) +>>> Line comment after dot. +variable = . // Comment. +whoDoesThis(); +<<< 3.9 +variable = + . // Comment. + whoDoesThis(); +>>> Block comment after dot. +variable = ./* Comment. */whoDoesThis(); +<<< 3.9 +variable = + . /* Comment. */ whoDoesThis(); +>>> Line comment after `const`. +variable = const // Comment. +. whoDoesThis(); +<<< 3.9 +variable = + const // Comment. + .whoDoesThis(); +>>> Block comment after `const`. +variable = const/* Comment. */.whoDoesThis(); +<<< 3.9 +variable = + const /* Comment. */ .whoDoesThis();