Merge branch 'expression-function-as-arg' of https://github.com/a14n/dart_style into a14n-expression-function-as-arg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fae032d..b765aa4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,24 @@
+# 1.2.7
+
+* Improve indentation of adjacent strings inside `=>` functions.
+
# 1.2.6
* Properly format trailing commas in assertions.
+* Improve indentation of adjacent strings. This fixes a regression introduced
+ in 1.2.5 and hopefully makes adjacent strings generally look better.
+
+ Adjacent strings in argument lists now format the same regardless of whether
+ the argument list contains a trailing comma. The rule is that if the
+ argument list contains no other strings, then the adjacent strings do not
+ get extra indentation. This keeps them lined up when doing so is unlikely to
+ be confused as showing separate independent string arguments.
+
+ Previously, adjacent strings were never indented in argument lists without a
+ trailing comma and always in argument lists that did. With this change,
+ adjacent strings are still always indented in collection literals because
+ readers are likely to interpret a series of unindented lines there as showing
+ separate collection elements.
# 1.2.5
diff --git a/bin/format.dart b/bin/format.dart
index 675fd11..5a70dc4 100644
--- a/bin/format.dart
+++ b/bin/format.dart
@@ -15,7 +15,7 @@
import 'package:dart_style/src/style_fix.dart';
// Note: The following line of code is modified by tool/grind.dart.
-const version = "1.2.5";
+const version = "1.2.7";
void main(List<String> args) {
var parser = ArgParser(allowTrailingOptions: true);
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index 4824302..2cf93c4 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -6,6 +6,7 @@
import 'dart:math' as math;
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/error/error.dart';
@@ -88,6 +89,12 @@
SourceCode formatSource(SourceCode source) {
var errorListener = ErrorListener();
+ // Enable all features that are enabled by default in the current analyzer
+ // version.
+ // TODO(paulberry): consider plumbing in experiment enable flags from the
+ // command line.
+ var featureSet = FeatureSet.fromEnableFlags([]);
+
// Tokenize the source.
var reader = CharSequenceReader(source.text);
var stringSource = StringSource(source.text, source.uri);
@@ -111,11 +118,9 @@
errorListener.throwIfErrors();
// Parse it.
- var parser = Parser(stringSource, errorListener);
+ var parser = Parser(stringSource, errorListener, featureSet: featureSet);
parser.enableOptionalNewAndConst = true;
parser.enableSetLiterals = true;
- parser.enableSpreadCollections = true;
- parser.enableControlFlowCollections = true;
AstNode node;
if (source.isCompilationUnit) {
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index e31aa50..184b4fb 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -186,9 +186,70 @@
}
visitAdjacentStrings(AdjacentStrings node) {
+ // We generally want to indent adjacent strings because it can be confusing
+ // otherwise when they appear in a list of expressions, like:
+ //
+ // [
+ // "one",
+ // "two"
+ // "three",
+ // "four"
+ // ]
+ //
+ // Especially when these stings are longer, it can be hard to tell that
+ // "three" is a continuation of the previous argument.
+ //
+ // However, the indentation is distracting in argument lists that don't
+ // suffer from this ambiguity:
+ //
+ // test(
+ // "A very long test description..."
+ // "this indentation looks bad.", () { ... });
+ //
+ // To balance these, we omit the indentation when an adjacent string
+ // expression is the only string in an argument list.
+ var shouldNest = true;
+
+ var parent = node.parent;
+ if (parent is ArgumentList) {
+ shouldNest = false;
+
+ for (var argument in parent.arguments) {
+ if (argument == node) continue;
+ if (argument is StringLiteral) {
+ shouldNest = true;
+ break;
+ }
+ }
+ } else if (parent is Assertion) {
+ // Treat asserts like argument lists.
+ shouldNest = false;
+ if (parent.condition != node && parent.condition is StringLiteral) {
+ shouldNest = true;
+ }
+
+ if (parent.message != node && parent.message is StringLiteral) {
+ shouldNest = true;
+ }
+ } else if (parent is VariableDeclaration ||
+ parent is AssignmentExpression &&
+ parent.rightHandSide == node &&
+ parent.parent is ExpressionStatement) {
+ // Don't add extra indentation in a variable initializer or assignment:
+ //
+ // var variable =
+ // "no extra"
+ // "indent";
+ shouldNest = false;
+ } else if (parent is NamedExpression || parent is ExpressionFunctionBody) {
+ shouldNest = false;
+ }
+
builder.startSpan();
builder.startRule();
+ if (shouldNest) builder.nestExpression();
visitNodes(node.strings, between: splitOrNewline);
+ if (shouldNest) builder.unnest();
builder.endRule();
builder.endSpan();
}
diff --git a/pubspec.yaml b/pubspec.yaml
index f13b8de..b1d58e5 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: 1.2.6-dev
+version: 1.2.8-dev
author: Dart Team <misc@dartlang.org>
description: >-
Opinionated, automatic Dart source code formatter.
@@ -11,7 +11,7 @@
sdk: '>=2.1.0 <3.0.0'
dependencies:
- analyzer: '>=0.36.0 <0.37.0'
+ analyzer: '>=0.36.3 <0.37.0'
args: '>=0.12.1 <2.0.0'
path: ^1.0.0
source_span: ^1.4.0
diff --git a/test/regression/0100/0185.stmt b/test/regression/0100/0185.stmt
index aac3da2..29a2b7a 100644
--- a/test/regression/0100/0185.stmt
+++ b/test/regression/0100/0185.stmt
@@ -9,6 +9,6 @@
const NO_DART_SCRIPT_AND_EXPERIMENTAL = const MessageTemplate(
const MessageId('polymer', 6),
'The experimental bootstrap feature doesn\'t support script tags on '
- 'the main document (for now).',
+ 'the main document (for now).',
'Script tags with experimental bootstrap',
'This experimental feature is no longer supported.');
\ No newline at end of file
diff --git a/test/regression/0200/0211.unit b/test/regression/0200/0211.unit
index 01766d8..aad9674 100644
--- a/test/regression/0200/0211.unit
+++ b/test/regression/0200/0211.unit
@@ -24,7 +24,7 @@
JS(
'void',
'Object.defineProperty(#, #, '
- '{value: #, enumerable: false, writable: true, configurable: true})',
+ '{value: #, enumerable: false, writable: true, configurable: true})',
obj,
property,
value);
diff --git a/test/regression/0700/0705.stmt b/test/regression/0700/0705.stmt
new file mode 100644
index 0000000..38f2fd2
--- /dev/null
+++ b/test/regression/0700/0705.stmt
@@ -0,0 +1,10 @@
+>>>
+final _appUrl = Platform.isIOS
+ ? 'https://itunes.apple.com/us/app/google-adwords/id1037457231'
+ : 'https://play.google.com/store/apps/details?id=com.google.android.apps.'
+ 'adwords';
+<<<
+final _appUrl = Platform.isIOS
+ ? 'https://itunes.apple.com/us/app/google-adwords/id1037457231'
+ : 'https://play.google.com/store/apps/details?id=com.google.android.apps.'
+ 'adwords';
\ No newline at end of file
diff --git a/test/regression/0700/0799.unit b/test/regression/0700/0799.unit
new file mode 100644
index 0000000..acd54a4
--- /dev/null
+++ b/test/regression/0700/0799.unit
@@ -0,0 +1,14 @@
+>>>
+@ShouldThrow(
+ 'Could not generate `toJson` code for `watch`.\n'
+ 'None of the provided `TypeHelper` instances support the defined type.',
+ configurations: ['default'],
+)
+class C {}
+<<<
+@ShouldThrow(
+ 'Could not generate `toJson` code for `watch`.\n'
+ 'None of the provided `TypeHelper` instances support the defined type.',
+ configurations: ['default'],
+)
+class C {}
\ No newline at end of file
diff --git a/test/regression/0800/0802.unit b/test/regression/0800/0802.unit
new file mode 100644
index 0000000..6e7323e
--- /dev/null
+++ b/test/regression/0800/0802.unit
@@ -0,0 +1,24 @@
+>>>
+class C {
+ @override
+ String get message =>
+ 'Unrecognized keys: [${unrecognizedKeys.join(', ')}]; supported keys: '
+ '[${allowedKeys.join(', ')}]';
+}
+<<<
+class C {
+ @override
+ String get message =>
+ 'Unrecognized keys: [${unrecognizedKeys.join(', ')}]; supported keys: '
+ '[${allowedKeys.join(', ')}]';
+}
+>>>
+String _link(String version, String owner, String name) =>
+ '${_anchorUriForName(owner, name)}: '
+ 'https://pub.dartlang.org/documentation/json_annotation/$version/'
+ 'json_annotation/$owner/$name.html';
+<<<
+String _link(String version, String owner, String name) =>
+ '${_anchorUriForName(owner, name)}: '
+ 'https://pub.dartlang.org/documentation/json_annotation/$version/'
+ 'json_annotation/$owner/$name.html';
\ No newline at end of file
diff --git a/test/regression/other/flutter.unit b/test/regression/other/flutter.unit
new file mode 100644
index 0000000..98dbde8
--- /dev/null
+++ b/test/regression/other/flutter.unit
@@ -0,0 +1,18 @@
+>>>
+const Vendor _trevor = Vendor(
+ name: 'Trevor’s shop',
+ avatarAsset: 'people/square/trevor.png',
+ avatarAssetPackage: _kGalleryAssetsPackage,
+ description:
+ 'Trevor makes great stuff for awesome people like you. Super cool and extra '
+ 'awesome all of his shop’s goods are handmade with love. Custom orders are '
+ 'available upon request if you need something extra special.');
+<<<
+const Vendor _trevor = Vendor(
+ name: 'Trevor’s shop',
+ avatarAsset: 'people/square/trevor.png',
+ avatarAssetPackage: _kGalleryAssetsPackage,
+ description:
+ 'Trevor makes great stuff for awesome people like you. Super cool and extra '
+ 'awesome all of his shop’s goods are handmade with love. Custom orders are '
+ 'available upon request if you need something extra special.');
\ No newline at end of file
diff --git a/test/whitespace/adjacent_strings.stmt b/test/whitespace/adjacent_strings.stmt
new file mode 100644
index 0000000..b368189
--- /dev/null
+++ b/test/whitespace/adjacent_strings.stmt
@@ -0,0 +1,258 @@
+40 columns |
+>>> do not indent adjacent strings if other args are not strings
+function(
+ notString,
+ "adjacent"
+ "string");
+<<<
+function(
+ notString,
+ "adjacent"
+ "string");
+>>> do not indent adjacent strings if other args are not strings
+function(
+ notString,
+ "adjacent"
+ "string",);
+<<<
+function(
+ notString,
+ "adjacent"
+ "string",
+);
+>>> do indent adjacent strings if other arg is string
+function(
+ "string",
+ notString,
+ "adjacent"
+ "string");
+<<<
+function(
+ "string",
+ notString,
+ "adjacent"
+ "string");
+>>> do indent adjacent strings if other arg is string
+function(
+ "string",
+ notString,
+ "adjacent"
+ "string",);
+<<<
+function(
+ "string",
+ notString,
+ "adjacent"
+ "string",
+);
+>>> do indent adjacent strings if other arg is string interpolation
+function(
+ "${str}${ing}",
+ notString,
+ "adjacent"
+ "string");
+<<<
+function(
+ "${str}${ing}",
+ notString,
+ "adjacent"
+ "string");
+>>> do indent adjacent strings if other arg is adjacent string
+function(
+ "adjacent"
+ "string",
+ notString,
+ "adjacent"
+ "string");
+<<<
+function(
+ "adjacent"
+ "string",
+ notString,
+ "adjacent"
+ "string");
+>>> always indent adjacent strings in list
+var list = [
+ "adjacent"
+ "string",
+ "another"
+ "adjacent"
+ "string"
+];
+<<<
+var list = [
+ "adjacent"
+ "string",
+ "another"
+ "adjacent"
+ "string"
+];
+>>> always indent adjacent strings in map key
+var map = {
+ "adjacent"
+ "string": value,
+ "another"
+ "adjacent"
+ "string": value
+};
+<<<
+var map = {
+ "adjacent"
+ "string": value,
+ "another"
+ "adjacent"
+ "string": value
+};
+>>> always indent adjacent strings in map value
+var map = {
+ key: "adjacent"
+ "string",
+ key: "another"
+ "adjacent"
+ "string"
+};
+<<<
+var map = {
+ key: "adjacent"
+ "string",
+ key: "another"
+ "adjacent"
+ "string"
+};
+>>> always indent adjacent strings in set
+var set = {
+ "adjacent"
+ "string",
+ "another"
+ "adjacent"
+ "string"
+};
+<<<
+var set = {
+ "adjacent"
+ "string",
+ "another"
+ "adjacent"
+ "string"
+};
+>>> don't indent in => body
+main() => "adjacent"
+"string"
+"another";
+<<<
+main() => "adjacent"
+ "string"
+ "another";
+>>> don't indent in long => body
+main() => "very very very very long adjacent"
+"string"
+"another";
+<<<
+main() =>
+ "very very very very long adjacent"
+ "string"
+ "another";
+>>> don't indent in => lambda
+function(
+ (parameter) => "string"
+ "adjacent",
+ (parameter) => "long long long long string"
+ "adjacent",
+ another);
+<<<
+function(
+ (parameter) => "string"
+ "adjacent",
+ (parameter) =>
+ "long long long long string"
+ "adjacent",
+ another);
+>>> indent in then branch of ?:
+var string = c ? "adjacent"
+"string" : "other";
+<<<
+var string = c
+ ? "adjacent"
+ "string"
+ : "other";
+>>> indent in else branch of ?:
+var string = c ? "other" : "adjacent"
+"string";
+<<<
+var string = c
+ ? "other"
+ : "adjacent"
+ "string";
+>>> don't indent in initializer
+var longVariableName = "very long adjacent"
+"string";
+<<<
+var longVariableName =
+ "very long adjacent"
+ "string";
+>>> don't indent assignment in statement position
+long.receiver.expression = "very long adjacent"
+"string";
+<<<
+long.receiver.expression =
+ "very long adjacent"
+ "string";
+>>> string interpolation counts as a string
+function(
+ "adjacent"
+ "string",
+ "${str}${ing}");
+<<<
+function(
+ "adjacent"
+ "string",
+ "${str}${ing}");
+>>> another adjacent string counts as a string
+function(
+ "adjacent"
+ "string",
+ "another"
+ "adjacent");
+<<<
+function(
+ "adjacent"
+ "string",
+ "another"
+ "adjacent");
+>>> do not indent adjacent strings in assert if other args are not strings
+assert(
+ condition,
+ "adjacent"
+ "string");
+<<<
+assert(
+ condition,
+ "adjacent"
+ "string");
+>>> don't need extra indentation inside named arguments
+function(named: "adjacent"
+"string",
+another: "adjacent"
+"string"
+"more");
+<<<
+function(
+ named: "adjacent"
+ "string",
+ another: "adjacent"
+ "string"
+ "more");
+>>> don't need extra indentation inside named arguments
+function(named: "adjacent"
+"string",
+another: "adjacent"
+"string"
+"more",);
+<<<
+function(
+ named: "adjacent"
+ "string",
+ another: "adjacent"
+ "string"
+ "more",
+);
\ No newline at end of file