diff --git a/lib/src/front_end/piece_factory.dart b/lib/src/front_end/piece_factory.dart index 337f51b9..b2f2cc3e 100644 --- a/lib/src/front_end/piece_factory.dart +++ b/lib/src/front_end/piece_factory.dart @@ -812,8 +812,26 @@ mixin PieceFactory { pieces.visit(directive.uri); }); - // Include the `as` clause. + // Add all of the clauses and combinators. var clauses = []; + + // The language specifies that configurations must appear after any `as` + // clause but the parser incorrectly accepts them before it and code in + // the wild relies on that. Instead of failing with an "unexpected output" + // error, just preserve the order of the clauses if they are out of order. + // See: https://github.com/dart-lang/sdk/issues/56641 + var wroteConfigurations = false; + if (directive.configurations.isNotEmpty && + asKeyword != null && + directive.configurations.first.ifKeyword.offset < asKeyword.offset) { + for (var configuration in directive.configurations) { + clauses.add(nodePiece(configuration)); + } + + wroteConfigurations = true; + } + + // Include the `as` clause. if (asKeyword != null) { clauses.add(pieces.build(() { pieces.token(deferredKeyword, spaceAfter: true); @@ -824,8 +842,10 @@ mixin PieceFactory { } // Include any `if` clauses. - for (var configuration in directive.configurations) { - clauses.add(nodePiece(configuration)); + if (!wroteConfigurations) { + for (var configuration in directive.configurations) { + clauses.add(nodePiece(configuration)); + } } // Include the `show` and `hide` clauses. diff --git a/lib/src/short/source_visitor.dart b/lib/src/short/source_visitor.dart index 3102b613..a2a30174 100644 --- a/lib/src/short/source_visitor.dart +++ b/lib/src/short/source_visitor.dart @@ -1955,6 +1955,19 @@ class SourceVisitor extends ThrowingAstVisitor { space(); visit(node.uri); + // The language specifies that configurations must appear after any `as` + // clause but the parser incorrectly accepts them before it and code in + // the wild relies on that. Instead of failing with an "unexpected output" + // error, just preserve the order of the clauses if they are out of order. + // See: https://github.com/dart-lang/sdk/issues/56641 + var wroteConfigurations = false; + if (node.asKeyword case var asKeyword? + when node.configurations.isNotEmpty && + node.configurations.first.ifKeyword.offset < asKeyword.offset) { + _visitConfigurations(node.configurations); + wroteConfigurations = true; + } + if (node.asKeyword != null) { soloSplit(); token(node.deferredKeyword, after: space); @@ -1963,7 +1976,10 @@ class SourceVisitor extends ThrowingAstVisitor { visit(node.prefix); } - _visitConfigurations(node.configurations); + if (!wroteConfigurations) { + _visitConfigurations(node.configurations); + } + _visitCombinators(node.combinators); }); } diff --git a/test/short/whitespace/directives.unit b/test/short/whitespace/directives.unit index 85116f33..d67313f5 100644 --- a/test/short/whitespace/directives.unit +++ b/test/short/whitespace/directives.unit @@ -70,4 +70,13 @@ part of 'uri.dart'; import 'foo.dart' as foo if (config == 'value') 'other.dart'; <<< import 'foo.dart' as foo - if (config == 'value') 'other.dart'; \ No newline at end of file + if (config == 'value') 'other.dart'; +>>> Configuration before prefix. +### This violates the language spec, but the parser currently allows it without +### reporting an error and code in the wild relies on that. So the formatter +### handles it gracefully. See: https://github.com/dart-lang/sdk/issues/56641 +import 'foo.dart' if (config == 'value') 'other.dart' as foo; +<<< +import 'foo.dart' + if (config == 'value') 'other.dart' + as foo; \ No newline at end of file diff --git a/test/tall/top_level/import.unit b/test/tall/top_level/import.unit index ee1830e9..6cdef861 100644 --- a/test/tall/top_level/import.unit +++ b/test/tall/top_level/import.unit @@ -73,4 +73,13 @@ import 'foo.dart' as foo if (config == 'value') 'other.dart'; <<< import 'foo.dart' as foo - if (config == 'value') 'other.dart'; \ No newline at end of file + if (config == 'value') 'other.dart'; +>>> Configuration before prefix. +### This violates the language spec, but the parser currently allows it without +### reporting an error and code in the wild relies on that. So the formatter +### handles it gracefully. See: https://github.com/dart-lang/sdk/issues/56641 +import 'foo.dart' if (config == 'value') 'other.dart' as foo; +<<< +import 'foo.dart' + if (config == 'value') 'other.dart' + as foo; \ No newline at end of file