diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart index 6ab5238a..215a9825 100644 --- a/lib/src/dart_formatter.dart +++ b/lib/src/dart_formatter.dart @@ -193,9 +193,15 @@ final class DartFormatter { // Format it. var lineInfo = parseResult.lineInfo; + // If the code has an `@dart=` comment, use that to determine the style. + var sourceLanguageVersion = languageVersion; + if (parseResult.unit.languageVersionToken case var token?) { + sourceLanguageVersion = Version(token.major, token.minor, 0); + } + // Use language version to determine what formatting style to apply. SourceCode output; - if (languageVersion > latestShortStyleLanguageVersion) { + if (sourceLanguageVersion > latestShortStyleLanguageVersion) { // Look for a page width comment before the code. int? pageWidthFromComment; for (Token? comment = node.beginToken.precedingComments; diff --git a/test/cli/language_version_test.dart b/test/cli/language_version_test.dart index 3c874dd7..0b179eeb 100644 --- a/test/cli/language_version_test.dart +++ b/test/cli/language_version_test.dart @@ -266,5 +266,62 @@ main() { await d.dir('code', [d.file('a.dart', after)]).validate(); }); + + test('language version comment override opts into short style', () async { + const before = ''' +// @dart=3.6 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.6 +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(); + }); + + test('language version comment override opts into tall style', () async { + // Note that in real-world code it doesn't make sense for a language + // version comment to be *higher* than the specified default language + // version before you can't use a comment that's higher than the minimum + // version in the package's SDK constraint. (Otherwise, you could end up + // trying to run a library whose language version isn't supported by the + // SDK you are running it in.) + // + // But we support it in the formatter since it's possible to specify a + // default language version using mechanisms other than the pubspec SDK + // constraint. + const before = ''' +// @dart=3.7 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.7 +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(); + }); }); } diff --git a/test/dart_formatter_test.dart b/test/dart_formatter_test.dart index 76a3c1ed..bf9c347b 100644 --- a/test/dart_formatter_test.dart +++ b/test/dart_formatter_test.dart @@ -81,6 +81,62 @@ main() { }); }); + test('language version comment override opts into short style', () async { + // Use a language version with tall style. + var formatter = makeFormatter(languageVersion: Version(3, 7, 0)); + + // But the code has a comment to opt into the short style. + const before = ''' +// @dart=3.6 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.6 +main() { + f( + argument, // comment + another); +} +'''; + + expect(formatter.format(before), after); + }); + + test('language version comment override opts into tall style', () async { + // Use a language version with short style. + var formatter = makeFormatter(languageVersion: Version(3, 6, 0)); + + // But the code has a comment to opt into the tall style. + // + // Note that in real-world code it doesn't make sense for a language + // version comment to be *higher* than the specified default language + // version before you can't use a comment that's higher than the minimum + // version in the package's SDK constraint. (Otherwise, you could end up + // trying to run a library whose language version isn't supported by the + // SDK you are running it in.) + // + // But we support it in the formatter since it's possible to specify a + // default language version using mechanisms other than the pubspec SDK + // constraint. + const before = ''' +// @dart=3.7 +main() { f(argument, // comment +another);} +'''; + const after = ''' +// @dart=3.7 +main() { + f( + argument, // comment + another, + ); +} +'''; + + expect(formatter.format(before), after); + }); + test('throws a FormatterException on failed parse', () { var formatter = makeFormatter(); expect(() => formatter.format('wat?!'), throwsA(isA()));