diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b242d47..b2bc5264 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,87 @@ ## 3.0.0-wip +This is a large change. Under the hood, the formatter was almost completely +rewritten, with the codebase now containing both the old and new +implementations. The old formatter exists to support the older "short" style +and the new code implements [the new "tall" style][tall]. + +[tall]: https://github.com/dart-lang/dart_style/issues/1253 + +The formatter uses the language version of the formatted code to determine +which style you get. If the language version is 3.6 or lower, the code is +formatted with the old style. If 3.7 or later, you get the new tall style. You +typically control the language version by [setting a min SDK constraint in your +package's pubspec][versioning]. + +[versioning]: https://dart.dev/guides/language/evolution + +In addition to the new formatting style, a number of other API and CLI changes +are included, some of them breaking: + +* **Support project-wide page width configuration.** By long request, you can + now configure your preferred formatting page width on a project-wide basis. + When formatting files, the formatter will look in the file's directory and + any surrounding directories for an `analysis_options.yaml` file. If it finds + one, it looks for the following YAML: + + ```yaml + formatter: + page_width: 123 + ``` + + If it finds a `formatter` key containing a map with a `page_width` key whose + value is an integer, then that is the page width that the file is formatted + using. Since the formatter will walk the surrounding directories until it + finds an `analysis_options.yaml` file, this can be used to globally set the + page width for an entire directory, package, or even collection of packages. + +* **Support overriding the page width for a single file.** In code formatted + using the new tall style, you can use a special marker comment to control the + page width that it's formatted using: + + ```dart + // dart format width=30 + main() { + someExpression + + thatSplitsAt30; + } + ``` + + This comment must appear before any code in the file and must match that + format exactly. The width set by the comment overrides the width set by any + surrounding `analysis_options.yaml` file. + + This feature is mainly for code generators that generate and immediately + format code but don't know what about any surrounding `analysis_options.yaml` + that might be configuring the page width. By inserting this comment in the + generated code before formatting, it ensures that the code generator's + behavior matches the behavior of `dart format`. + + End users should mostly use `analysis_options.yaml` for configuring their + preferred page width (or do nothing and use the default page width of 80). + +* **Support opting out a region of code from formatting.** In code formatted + using the new tall style, you can use a pair of special marker comments to + opt a region of code out of automated formatting: + + ```dart + main() { + this.isFormatted(); + // dart format off + no + formatting + + + here; + // dart format on + formatting.isBackOnHere(); + } + ``` + + The comments must be exactly `// dart format off` and `// dart format on`. + A file may have multiple regions, but they can't overlap or nest. + + This can be useful for highly structured data where custom layout can help + a reader understand the data, like large lists of numbers. + * **Remove support for fixes and `--fix`.** The tools that come with the Dart SDK provide two ways to apply automated changes to code: `dart format --fix` and `dart fix`. The former is older and used to be faster. But it can only @@ -16,21 +98,20 @@ * **Make the language version parameter to `DartFormatter()` mandatory.** This way, the formatter always knows what language version the input is intended - to be treated as. Note that a `// @dart=` language version comment if present - overrides the specified language version. You can think of the version passed - to the `DartFormatter()` constructor as a "default" language version which - the file's contents may then override. + to be treated as. Note that a `// @dart=` language version comment, if + present, overrides the specified language version. You can think of the + version passed to the `DartFormatter()` constructor as a "default" language + version which the file's contents may then override. If you don't particularly care about the version of what you're formatting, you can pass in `DartFormatter.latestLanguageVersion` to unconditionally get the latest language version that the formatter supports. Note that doing so - means you will also implicitly opt into the new tall style when that style - becomes available. + means you will also implicitly opt into the new tall style. This change only affects the library API. When using the formatter from the command line, you can use `--language-version=` to specify a language version or pass `--language-version=latest` to use the latest supported version. If - omitted, the formatter will look up the surrounding directories for a package + omitted, the formatter will look in the surrounding directories for a package config file and infer the language version for the package from that, similar to how other Dart tools behave like `dart analyze` and `dart run`. @@ -38,9 +119,8 @@ `dart format` command was added to the core Dart SDK, users accessed the formatter by running a separate `dartfmt` executable that was included with the Dart SDK. That executable had a different CLI interface. For example, you - had to pass `-w` to get it to overwrite files and if you passed no arguments - at all, it silently sat there waiting for input on stdin. When we added - `dart format`, we took that opportunity to revamp the CLI options. + had to pass `-w` to get it to overwrite files. When we added `dart format`, + we took that opportunity to revamp the CLI options. However, the dart_style package still exposed an executable with the old CLI. If you ran `dart pub global activate dart_style`, this would give you a @@ -64,14 +144,8 @@ `--language-version=`, or use `--language-version=latest` to parse the input using the latest language version supported by the formatter. - If `--stdin-name` and `--language-version` are both omitted, then parses - stdin using the latest supported language version. - -* **Apply class modifiers to API classes.** The dart_style package exposes only - a few classes in its public API: `DartFormatter`, `SourceCode`, - `FormatterException`, and `UnexpectedOutputException`. None were ever - intended to be extended or implemented. They are now all marked `final` to - make that intention explicit. + If `--stdin-name` and `--language-version` are both omitted, then the + formatter parses stdin using the latest supported language version. * **Rename the `--line-length` option to `--page-width`.** This is consistent with the public API, internal implementation, and docs, which all use "page @@ -79,10 +153,16 @@ The `--line-length` name is still supported for backwards compatibility, but may be removed at some point in the future. You're encouraged to move to - `--page-width`. Use of this option (however its named) is rare, and will + `--page-width`. Use of this option (however it's named) is rare, and will likely be even rarer now that project-wide configuration is supported, so this shouldn't affect many users. +* **Apply class modifiers to API classes.** The dart_style package exposes only + a few classes in its public API: `DartFormatter`, `SourceCode`, + `FormatterException`, and `UnexpectedOutputException`. None were ever + intended to be extended or implemented. They are now all marked `final` to + make that intention explicit. + ## 2.3.7 * Allow passing a language version to `DartFomatter()`. Formatted code will be diff --git a/benchmark/directory.dart b/benchmark/directory.dart index d1d051d5..536b75d4 100644 --- a/benchmark/directory.dart +++ b/benchmark/directory.dart @@ -7,7 +7,6 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:collection/collection.dart'; import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:dart_style/src/profile.dart'; import 'package:dart_style/src/testing/benchmark.dart'; @@ -64,8 +63,9 @@ void main(List arguments) async { void _runFormatter(String source) { try { var formatter = DartFormatter( - languageVersion: DartFormatter.latestLanguageVersion, - experimentFlags: [if (!_isShort) tallStyleExperimentFlag]); + languageVersion: _isShort + ? DartFormatter.latestShortStyleLanguageVersion + : DartFormatter.latestLanguageVersion); var result = formatter.format(source); diff --git a/benchmark/run.dart b/benchmark/run.dart index e19ff788..2d385398 100644 --- a/benchmark/run.dart +++ b/benchmark/run.dart @@ -10,7 +10,6 @@ import 'package:analyzer/dart/analysis/results.dart'; import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:args/args.dart'; import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:dart_style/src/debug.dart' as debug; import 'package:dart_style/src/front_end/ast_node_visitor.dart'; import 'package:dart_style/src/profile.dart'; @@ -131,10 +130,11 @@ List _runTrials(String verb, Benchmark benchmark, int trials) { throwIfDiagnostics: false); var formatter = DartFormatter( - languageVersion: DartFormatter.latestLanguageVersion, + languageVersion: _isShort + ? DartFormatter.latestShortStyleLanguageVersion + : DartFormatter.latestLanguageVersion, pageWidth: benchmark.pageWidth, - lineEnding: '\n', - experimentFlags: [if (!_isShort) tallStyleExperimentFlag]); + lineEnding: '\n'); var measuredTimes = []; for (var i = 1; i <= trials; i++) { diff --git a/example/format.dart b/example/format.dart index ad2d004d..ec1cea23 100644 --- a/example/format.dart +++ b/example/format.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:dart_style/src/debug.dart' as debug; import 'package:dart_style/src/testing/test_file.dart'; @@ -40,9 +39,10 @@ void _runFormatter(String source, int pageWidth, {required bool tall, required bool isCompilationUnit}) { try { var formatter = DartFormatter( - languageVersion: DartFormatter.latestLanguageVersion, - pageWidth: pageWidth, - experimentFlags: [if (tall) tallStyleExperimentFlag]); + languageVersion: tall + ? DartFormatter.latestShortStyleLanguageVersion + : DartFormatter.latestLanguageVersion, + pageWidth: pageWidth); String result; if (isCompilationUnit) { @@ -75,10 +75,7 @@ Future _runTest(String path, int line, var formatter = DartFormatter( languageVersion: formatTest.languageVersion, pageWidth: testFile.pageWidth, - indent: formatTest.leadingIndent, - experimentFlags: tall - ? const ['inline-class', tallStyleExperimentFlag] - : const ['inline-class']); + indent: formatTest.leadingIndent); var actual = formatter.formatSource(formatTest.input); diff --git a/lib/src/cli/format_command.dart b/lib/src/cli/format_command.dart index 323c0853..f543d0ac 100644 --- a/lib/src/cli/format_command.dart +++ b/lib/src/cli/format_command.dart @@ -69,8 +69,7 @@ final class FormatCommand extends Command { help: 'Language version of formatted code.\n' 'Use "latest" to parse as the latest supported version.\n' 'Omit to look for a surrounding package config.', - // TODO(rnystrom): Show this when the tall-style experiment ships. - hide: true); + hide: !verbose); argParser.addFlag('set-exit-if-changed', negatable: false, diff --git a/lib/src/config_cache.dart b/lib/src/config_cache.dart index 1d039ae9..0c4a93a5 100644 --- a/lib/src/config_cache.dart +++ b/lib/src/config_cache.dart @@ -62,6 +62,7 @@ final class ConfigCache { // Otherwise, walk the file system and look for it. var config = await _findPackageConfig(file, displayPath, forLanguageVersion: true); + if (config?.packageOf(file.absolute.uri)?.languageVersion case var languageVersion?) { // Store the version as pub_semver's [Version] type because that's diff --git a/lib/src/constants.dart b/lib/src/constants.dart index 59e20859..1a249623 100644 --- a/lib/src/constants.dart +++ b/lib/src/constants.dart @@ -2,15 +2,6 @@ // 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. -/// The in-progress "tall" formatting style is enabled by passing an experiment -/// flag with this name. -/// -/// Note that this isn't a real Dart SDK experiment: Only the formatter supports -/// it. We use the [experimentFlags] API to pass this in so that support for it -/// can be removed in a later version without it being a breaking change to the -/// dart_style library API. -const tallStyleExperimentFlag = 'tall-style'; - /// Constants for the cost heuristics used to determine which set of splits is /// most desirable. final class Cost { diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart index 44c06331..e8cdb7eb 100644 --- a/lib/src/dart_formatter.dart +++ b/lib/src/dart_formatter.dart @@ -14,7 +14,6 @@ import 'package:analyzer/src/dart/scanner/scanner.dart'; import 'package:analyzer/src/string_source.dart'; import 'package:pub_semver/pub_semver.dart'; -import 'constants.dart'; import 'exceptions.dart'; import 'front_end/ast_node_visitor.dart'; import 'short/source_visitor.dart'; @@ -30,7 +29,14 @@ 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, 3, 0); + static final latestLanguageVersion = Version(3, 7, 0); + + /// The latest Dart language version that will be formatted using the older + /// "short" style. + /// + /// Any Dart code at a language version later than this will be formatted + /// using the new "tall" style. + static final latestShortStyleLanguageVersion = Version(3, 6, 0); /// The page width that the formatter tries to fit code inside if no other /// width is specified. @@ -125,11 +131,8 @@ final class DartFormatter { ); } - // Don't pass the formatter's own experiment flag to the parser. - var experiments = experimentFlags.toList(); - experiments.remove(tallStyleExperimentFlag); var featureSet = FeatureSet.fromEnableFlags2( - sdkLanguageVersion: languageVersion, flags: experiments); + sdkLanguageVersion: languageVersion, flags: experimentFlags); // Parse it. var parseResult = parseString( @@ -185,8 +188,9 @@ final class DartFormatter { // Format it. var lineInfo = parseResult.lineInfo; + // Use language version to determine what formatting style to apply. SourceCode output; - if (experimentFlags.contains(tallStyleExperimentFlag)) { + if (languageVersion > latestShortStyleLanguageVersion) { // Look for a page width comment before the code. int? pageWidthFromComment; for (Token? comment = node.beginToken.precedingComments; @@ -203,6 +207,7 @@ final class DartFormatter { var visitor = AstNodeVisitor(this, lineInfo, unitSourceCode); output = visitor.run(unitSourceCode, node, pageWidthFromComment); } else { + // Use the old style. var visitor = SourceVisitor(this, lineInfo, unitSourceCode); output = visitor.run(node); } diff --git a/lib/src/io.dart b/lib/src/io.dart index 3089c4b0..243b308e 100644 --- a/lib/src/io.dart +++ b/lib/src/io.dart @@ -9,7 +9,6 @@ import 'package:path/path.dart' as p; import 'cli/formatter_options.dart'; import 'config_cache.dart'; -import 'constants.dart'; import 'dart_formatter.dart'; import 'exceptions.dart'; import 'source_code.dart'; @@ -25,14 +24,10 @@ Future formatStdin( selectionLength = selection[1]; } - ConfigCache? cache; - // TODO(rnystrom): Remove the experiment check when the experiment ships. - if (options.experimentFlags.contains(tallStyleExperimentFlag)) { - cache = ConfigCache(); - } + var cache = ConfigCache(); var languageVersion = options.languageVersion; - if (languageVersion == null && path != null && cache != null) { + if (languageVersion == null && path != null) { // We have a stdin-name, so look for a surrounding package config. languageVersion = await cache.findLanguageVersion(File(path), path); } @@ -43,7 +38,7 @@ Future formatStdin( // Determine the page width. var pageWidth = options.pageWidth; - if (pageWidth == null && path != null && cache != null) { + if (pageWidth == null && path != null) { // We have a stdin-name, so look for a surrounding analyisis_options.yaml. pageWidth = await cache.findPageWidth(File(path)); } @@ -92,12 +87,7 @@ $stack'''); Future formatPaths(FormatterOptions options, List paths) async { // If the user didn't specify a language version, then look for surrounding // package configs so we know what language versions to use for the files. - ConfigCache? cache; - // TODO(rnystrom): Remove the experiment check when the experiment ships and - // make cache non-nullable. - if (options.experimentFlags.contains(tallStyleExperimentFlag)) { - cache = ConfigCache(); - } + var cache = ConfigCache(); for (var path in paths) { var directory = Directory(path); @@ -125,7 +115,7 @@ Future formatPaths(FormatterOptions options, List paths) async { /// Returns `true` if successful or `false` if an error occurred in any of the /// files. Future _processDirectory( - ConfigCache? cache, FormatterOptions options, Directory directory) async { + ConfigCache cache, FormatterOptions options, Directory directory) async { var success = true; var entries = @@ -154,25 +144,20 @@ Future _processDirectory( /// /// Returns `true` if successful or `false` if an error occurred. Future _processFile( - ConfigCache? cache, FormatterOptions options, File file, + ConfigCache cache, FormatterOptions options, File file, {String? displayPath}) async { displayPath ??= file.path; // Determine what language version to use. - var languageVersion = options.languageVersion; - if (languageVersion == null && cache != null) { - languageVersion = await cache.findLanguageVersion(file, displayPath); - } + var languageVersion = options.languageVersion ?? + await cache.findLanguageVersion(file, displayPath); // If they didn't specify a version and we couldn't find a surrounding // package, then default to the latest version. languageVersion ??= DartFormatter.latestLanguageVersion; // Determine the page width. - var pageWidth = options.pageWidth; - if (pageWidth == null && cache != null) { - pageWidth = await cache.findPageWidth(file); - } + var pageWidth = options.pageWidth ?? await cache.findPageWidth(file); // Use a default page width if we don't have a specified one and couldn't // find a configured one. diff --git a/lib/src/testing/test_file.dart b/lib/src/testing/test_file.dart index a00a4504..053bb10f 100644 --- a/lib/src/testing/test_file.dart +++ b/lib/src/testing/test_file.dart @@ -99,8 +99,11 @@ final class TestFile { return ''; }); - // Let the test specify a language version to parse it at. - var languageVersion = DartFormatter.latestLanguageVersion; + // Let the test specify a language version to parse it at. If not, use + // a default version for the style being tested. + var languageVersion = p.split(file.path).contains('tall') + ? DartFormatter.latestLanguageVersion + : DartFormatter.latestShortStyleLanguageVersion; description = description.replaceAllMapped(_versionPattern, (match) { var major = int.parse(match[1]!); var minor = int.parse(match[2]!); diff --git a/test/README.md b/test/README.md index 0ec286fb..e665163c 100644 --- a/test/README.md +++ b/test/README.md @@ -4,7 +4,7 @@ an expected output. ## Formatting file format -The actual formatting logic live in test data files ending in ".unit" or +The formatting test expectations live in test data files ending in ".unit" or ".stmt". The ".unit" extension is for tests whose input should be parsed as an entire Dart compilation unit (roughly library or part file). The ".stmt" files parse each expectation as a statement. @@ -20,15 +20,15 @@ var a=1+2/(3*-b~/4); ``` If the first line contains a `|`, then it indicates the page width that all -tests in this file should be formatted using. All other text on that line are -ignored. This is mainly used so that tests can test line wrapping behavior -without having to create long code to force things to wrap. +tests in this file should be formatted using. All other text on that line is +ignored. This is used so that tests can test line wrapping behavior without +having to create long code to force things to wrap. The `>>>` line begins a test. It may have comment text afterwards describing the -test. If the line contains `(indent )` for some `n`, then formatter is told -to run with that level of indentation. This is mainly for regression tests where -the erroneous code appeared deeply nested inside some class or function and the -test wants to reproduce that same surrounding indentation. +test. If the line contains `(indent )` for some `n`, then the formatter is +told to run with that level of indentation. This is mainly for regression tests +where the erroneous code appeared deeply nested inside some class or function +and the test wants to reproduce that same surrounding indentation. Lines after the `>>>` line are the input code to be formatted. @@ -68,8 +68,8 @@ tall/declaration/ - Typedef, class, enum, extension, mixin, and member tall/expression/ - Expressions and collection elements. tall/function/ - Function declarations. tall/invocation/ - Function and member invocations. +tall/other/ - Selections, comment markers, and other odds and ends. tall/pattern/ - Patterns. -tall/selection/ - Test preserving selection information. tall/statement/ - Statements. tall/top_level/ - Top-level directives. tall/type/ - Type annotations. diff --git a/test/cli/language_version_test.dart b/test/cli/language_version_test.dart index e7ea7bb2..3c874dd7 100644 --- a/test/cli/language_version_test.dart +++ b/test/cli/language_version_test.dart @@ -29,9 +29,7 @@ extension type Meters(int value) { test('uses latest language version if no surrounding package', () async { await d.dir('code', [d.file('a.dart', extensionTypeBefore)]).create(); - // Enable the experiment to be sure that we're opting in to the new - // package config search. - var process = await runFormatterOnDir(['--enable-experiment=tall-style']); + var process = await runFormatterOnDir(); await process.shouldExit(0); await d.dir('code', [d.file('a.dart', extensionTypeAfter)]).validate(); @@ -75,24 +73,6 @@ main() { }); group('package config', () { - // TODO(rnystrom): Remove this test when the experiment ships. - test('no package search if experiment is off', () async { - // Put the file in a directory with a malformed package config. If we - // search for it, we should get an error. - await d.dir('foo', [ - d.dir('.dart_tool', [ - d.file('package_config.json', 'this no good json is bad json'), - ]), - d.file('main.dart', 'main(){ }'), - ]).create(); - - var process = await runFormatterOnDir(); - await process.shouldExit(0); - - // Should format the file without any error reading the package config. - await d.dir('foo', [d.file('main.dart', 'main() {}\n')]).validate(); - }); - test('no package search if language version is specified', () async { // Put the file in a directory with a malformed package config. If we // search for it, we should get an error. @@ -103,8 +83,7 @@ main() { d.file('main.dart', 'main(){ }'), ]).create(); - var process = await runFormatterOnDir( - ['--language-version=latest', '--enable-experiment=tall-style']); + var process = await runFormatterOnDir(['--language-version=latest']); await process.shouldExit(0); // Should format the file without any error reading the package config. @@ -112,18 +91,16 @@ main() { }); test('default to language version of surrounding package', () async { - // The package config sets the language version to 3.1, but the switch - // case uses a syntax which is valid in earlier versions of Dart but an - // error in 3.0 and later. Verify that the error is reported. + // The package config sets the language version to 2.19, but pattern + // variables are only available in 3.0 and later. Verify that the error + // is reported. await d.dir('foo', [ - packageConfig('foo', version: '3.1'), - d.file('main.dart', 'main() { switch (o) { case 1 + 2: break; } }'), + packageConfig('foo', version: '2.19'), + d.file('main.dart', 'main() { var (a, b) = (1, 2); }'), ]).create(); var path = p.join(d.sandbox, 'foo', 'main.dart'); - // TODO(rnystrom): Remove experiment flag when it ships. - var process = - await runFormatter([path, '--enable-experiment=tall-style']); + var process = await runFormatter([path]); expect(await process.stderr.next, 'Could not format because the source could not be parsed:'); @@ -170,8 +147,7 @@ main() { d.file('main.dart', 'main() {var (a,b)=(1,2);}'), ]).create(); - // TODO(rnystrom): Remove experiment flag when it ships. - var process = await runFormatterOnDir(['--enable-experiment=tall-style']); + var process = await runFormatterOnDir(); await process.shouldExit(0); // Formats the file. @@ -187,15 +163,14 @@ main() { group('stdin', () { test('infers language version from surrounding package', () async { - // The package config sets the language version to 3.1, but the switch - // case uses a syntax which is valid in earlier versions of Dart but an - // error in 3.0 and later. Verify that the error is reported. + // The package config sets the language version to 2.19, when switch + // cases still allowed arbitrary constant expressions like `1 + 2`. + // Verify that the code is formatted without error. await d.dir('foo', [ packageConfig('foo', version: '2.19'), ]).create(); - var process = await runFormatter( - ['--enable-experiment=tall-style', '--stdin-name=foo/main.dart']); + var process = await runFormatter(['--stdin-name=foo/main.dart']); // Write a switch whose syntax is valid in 2.19, but an error in later // versions. process.stdin.writeln('main() { switch (o) { case 1 + 2: break; } }'); @@ -222,8 +197,7 @@ main() { var process = await runFormatter([ '--language-version=2.19', - '--enable-experiment=tall-style', - '--stdin-name=foo/main.dart' + '--stdin-name=foo/main.dart', ]); // Write a switch whose syntax is valid in 2.19, but an error in later @@ -243,8 +217,7 @@ main() { test('use latest language version if no surrounding package', () async { await d.dir('foo', []).create(); - var process = await runFormatter( - ['--enable-experiment=tall-style', '--stdin-name=foo/main.dart']); + var process = await runFormatter(['--stdin-name=foo/main.dart']); // Use some relatively recent syntax. process.stdin.writeln('main() {var (a,b)=(1,2);}'); await process.stdin.close(); @@ -255,4 +228,43 @@ main() { await process.shouldExit(0); }); }); + + group('style', () { + test('uses the short style on 3.6 or earlier', () async { + const before = 'main() { f(argument, // comment\nanother);}'; + const after = ''' +main() { + f( + argument, // comment + another); +} +'''; + + await d.dir('code', [d.file('a.dart', before)]).create(); + + var process = await runFormatterOnDir(['--language-version=3.6']); + await process.shouldExit(0); + + await d.dir('code', [d.file('a.dart', after)]).validate(); + }); + + test('uses the tall style on 3.7 or earlier', () async { + const before = 'main() { f(argument, // comment\nanother);}'; + const after = ''' +main() { + f( + argument, // comment + another, + ); +} +'''; + + await d.dir('code', [d.file('a.dart', before)]).create(); + + var process = await runFormatterOnDir(['--language-version=3.7']); + await process.shouldExit(0); + + await d.dir('code', [d.file('a.dart', after)]).validate(); + }); + }); } diff --git a/test/cli/page_width_test.dart b/test/cli/page_width_test.dart index 44b72e8f..9d7fa53f 100644 --- a/test/cli/page_width_test.dart +++ b/test/cli/page_width_test.dart @@ -36,10 +36,7 @@ void main() { d.file('main.dart', _unformatted), ]).create(); - var process = await runFormatterOnDir([ - '--enable-experiment=tall-style', - '--page-width=30', - ]); + var process = await runFormatterOnDir(['--page-width=30']); await process.shouldExit(0); await d.dir('foo', [d.file('main.dart', _formatted30)]).validate(); @@ -50,40 +47,20 @@ void main() { d.file('main.dart', _unformatted), ]).create(); - var process = await runFormatterOnDir([ - '--enable-experiment=tall-style', - '--line-length=30', - ]); + var process = await runFormatterOnDir(['--line-length=30']); await process.shouldExit(0); await d.dir('foo', [d.file('main.dart', _formatted30)]).validate(); }); }); - test('no options search if experiment is off', () async { - await d.dir('foo', [ - analysisOptionsFile(pageWidth: 20), - d.file('main.dart', _unformatted), - ]).create(); - - var process = await runFormatterOnDir(); - await process.shouldExit(0); - - // Should format the file at the default width. - await d.dir('foo', [d.file('main.dart', _formatted80)]).validate(); - }); - test('no options search if page width is specified on the CLI', () async { await d.dir('foo', [ analysisOptionsFile(pageWidth: 20), d.file('main.dart', _unformatted), ]).create(); - var process = await runFormatterOnDir([ - '--language-version=latest', // Error to not have language version. - '--page-width=30', - '--enable-experiment=tall-style' - ]); + var process = await runFormatterOnDir(['--page-width=30']); await process.shouldExit(0); // Should format the file at 30, not 20 or 80. @@ -123,10 +100,7 @@ void main() { d.file('main.dart', _unformatted), ]).create(); - var process = await runFormatterOnDir([ - '--language-version=latest', // Error to not have language version. - '--enable-experiment=tall-style' - ]); + var process = await runFormatterOnDir(); await process.shouldExit(0); // Should format the file at 30. @@ -155,10 +129,7 @@ void main() { ]), ]).create(); - var process = await runFormatterOnDir([ - '--language-version=latest', // Error to not have language version. - '--enable-experiment=tall-style' - ]); + var process = await runFormatterOnDir(); await process.shouldExit(0); // Should format the file at 30. @@ -178,10 +149,7 @@ void main() { ]), ]).create(); - var process = await runFormatterOnDir([ - '--language-version=latest', // Error to not have language version. - '--enable-experiment=tall-style' - ]); + var process = await runFormatterOnDir(); await process.shouldExit(0); // Should format the file at 80. @@ -196,12 +164,7 @@ void main() { analysisOptionsFile(pageWidth: 30), ]).create(); - var process = await runFormatter([ - '--language-version=latest', // Error to not have language version. - '--enable-experiment=tall-style', - '--stdin-name=foo/main.dart', - ]); - + var process = await runFormatter(['--stdin-name=foo/main.dart']); process.stdin.writeln(_unformatted); await process.stdin.close(); @@ -219,10 +182,8 @@ void main() { ]).create(); var process = await runFormatter([ - '--language-version=latest', - '--enable-experiment=tall-style', '--page-width=30', - '--stdin-name=foo/main.dart' + '--stdin-name=foo/main.dart', ]); process.stdin.writeln(_unformatted); @@ -274,10 +235,7 @@ Future _testWithOptions(Object? options, d.file('main.dart', _unformatted), ]).create(); - var process = await runFormatterOnDir([ - '--language-version=latest', // Error to not have language version. - '--enable-experiment=tall-style' - ]); + var process = await runFormatterOnDir(); await process.shouldExit(0); // Should format the file at the expected width. diff --git a/test/dart_formatter_test.dart b/test/dart_formatter_test.dart index 9b97a799..76a3c1ed 100644 --- a/test/dart_formatter_test.dart +++ b/test/dart_formatter_test.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -21,22 +20,24 @@ void main() async { void _runTests({required bool isTall}) { DartFormatter makeFormatter( {Version? languageVersion, int? indent, String? lineEnding}) { + languageVersion ??= isTall + ? DartFormatter.latestLanguageVersion + : DartFormatter.latestShortStyleLanguageVersion; + return DartFormatter( - languageVersion: languageVersion ?? DartFormatter.latestLanguageVersion, + languageVersion: languageVersion, indent: indent, - lineEnding: lineEnding, - experimentFlags: [if (isTall) tallStyleExperimentFlag]); + lineEnding: lineEnding); } group('language version', () { test('defaults to latest if omitted', () { var formatter = makeFormatter(); - expect(formatter.languageVersion, DartFormatter.latestLanguageVersion); - }); - - test('defaults to latest if null', () { - var formatter = makeFormatter(languageVersion: null); - expect(formatter.languageVersion, DartFormatter.latestLanguageVersion); + expect( + formatter.languageVersion, + isTall + ? DartFormatter.latestLanguageVersion + : DartFormatter.latestShortStyleLanguageVersion); }); test('parses at given older language version', () { diff --git a/test/utils.dart b/test/utils.dart index e35c1296..9a4f3782 100644 --- a/test/utils.dart +++ b/test/utils.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:dart_style/src/testing/benchmark.dart'; import 'package:dart_style/src/testing/test_file.dart'; import 'package:path/path.dart' as p; @@ -97,11 +96,11 @@ Future testBenchmarks({required bool useTallStyle}) async { for (var benchmark in benchmarks) { test(benchmark.name, () { var formatter = DartFormatter( - languageVersion: DartFormatter.latestLanguageVersion, + languageVersion: useTallStyle + ? DartFormatter.latestLanguageVersion + : DartFormatter.latestShortStyleLanguageVersion, pageWidth: benchmark.pageWidth, - experimentFlags: useTallStyle - ? const ['inline-class', 'macros', tallStyleExperimentFlag] - : const ['inline-class', 'macros']); + experimentFlags: const ['macros']); var actual = formatter.formatSource(SourceCode(benchmark.input)); @@ -126,9 +125,6 @@ Future testBenchmarks({required bool useTallStyle}) async { } void _testFile(TestFile testFile) { - var useTallStyle = - testFile.path.startsWith('tall/') || testFile.path.startsWith('tall\\'); - group(testFile.path, () { for (var formatTest in testFile.tests) { test(formatTest.label, () { @@ -136,9 +132,7 @@ void _testFile(TestFile testFile) { languageVersion: formatTest.languageVersion, pageWidth: testFile.pageWidth, indent: formatTest.leadingIndent, - experimentFlags: useTallStyle - ? const ['inline-class', 'macros', tallStyleExperimentFlag] - : const ['inline-class', 'macros']); + experimentFlags: const ['macros']); var actual = formatter.formatSource(formatTest.input); @@ -174,7 +168,10 @@ void _testFile(TestFile testFile) { /// If [packages] is given, it should be a map from package names to root URIs /// for each package. d.DirectoryDescriptor packageConfig(String rootPackageName, - {String version = '3.5', Map? packages}) { + {String? version, Map? packages}) { + var defaultVersion = DartFormatter.latestLanguageVersion; + version ??= '${defaultVersion.major}.${defaultVersion.minor}'; + Map package(String name, String rootUri) => { 'name': name, 'rootUri': rootUri, diff --git a/tool/update_tests.dart b/tool/update_tests.dart index 9c8affcd..d96f4eb2 100644 --- a/tool/update_tests.dart +++ b/tool/update_tests.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:dart_style/dart_style.dart'; -import 'package:dart_style/src/constants.dart'; import 'package:dart_style/src/testing/test_file.dart'; import 'package:path/path.dart' as p; @@ -87,12 +86,6 @@ Future _updateTestFile(TestFile testFile) async { // Write the file-level comments. _writeComments(buffer, testFile.comments); - var experiments = [ - 'inline-class', - 'macros', - if (p.split(testFile.path).contains('tall')) tallStyleExperimentFlag - ]; - _totalTests += testFile.tests.length; for (var formatTest in testFile.tests) { @@ -100,7 +93,7 @@ Future _updateTestFile(TestFile testFile) async { languageVersion: formatTest.languageVersion, pageWidth: testFile.pageWidth, indent: formatTest.leadingIndent, - experimentFlags: experiments); + experimentFlags: const ['macros']); var actual = formatter.formatSource(formatTest.input); @@ -113,9 +106,13 @@ Future _updateTestFile(TestFile testFile) async { // Insert a newline between each test, but not after the last. if (formatTest != testFile.tests.first) buffer.writeln(); + var defaultLanguageVersion = p.split(testFile.path).contains('tall') + ? DartFormatter.latestLanguageVersion + : DartFormatter.latestShortStyleLanguageVersion; + var descriptionParts = [ if (formatTest.leadingIndent != 0) '(indent ${formatTest.leadingIndent})', - if (formatTest.languageVersion != DartFormatter.latestLanguageVersion) + if (formatTest.languageVersion != defaultLanguageVersion) '(version ${formatTest.languageVersion.major}.' '${formatTest.languageVersion.minor})', formatTest.description