@@ -18,15 +18,18 @@ import 'dart:isolate';
1818
1919import 'package:analyzer/dart/analysis/utilities.dart' ;
2020import 'package:analyzer/dart/ast/ast.dart' ;
21+ import 'package:analyzer/dart/ast/token.dart' show LanguageVersionToken;
2122import 'package:build/build.dart' ;
2223import 'package:dart_style/dart_style.dart' ;
2324import 'package:path/path.dart' as p;
2425import 'package:package_config/package_config.dart' as pc;
26+ import 'package:pub_semver/pub_semver.dart' as semver;
2527import 'package:source_span/source_span.dart' ;
2628
2729import './util.dart' ;
2830import 'codegen.dart' ;
2931import 'codegen/language_version_util.dart' ;
32+ import 'dart_style_compat.dart' ;
3033import 'parsing.dart' ;
3134
3235Builder overReactBuilder (BuilderOptions ? options) => OverReactBuilder ();
@@ -62,6 +65,7 @@ class OverReactBuilder extends Builder {
6265 return ;
6366 }
6467
68+ pc.LanguageVersion ? packageConfigLanguageVersion;
6569 String nullSafetyReason;
6670 bool nullSafety;
6771 {
@@ -84,7 +88,6 @@ class OverReactBuilder extends Builder {
8488 // Catch any errors coming from our implementation of `$packageConfig`.
8589 // We can remove this once we switch to build 2.4.0's `packageConfig`
8690 // (see `$packageConfig` doc comment for more info).
87- pc.LanguageVersion ? packageConfigLanguageVersion;
8891 try {
8992 packageConfigLanguageVersion = (await buildStep.$packageConfig)
9093 .packages
@@ -222,11 +225,30 @@ class OverReactBuilder extends Builder {
222225 final nullSafetyCommentText = 'Using nullSafety: $nullSafety .${nullSafety ? ' ' : '' } $nullSafetyReason ' ;
223226
224227 // Generated part files must have matching language version comments, so copy them over if they exist.
225- // TODO use CompilationUnit.languageVersionToken instead of parsing this manually once we're sure we can get on analyzer version 0.39.5 or greater
226- final languageVersionCommentMatch = RegExp (r'//\s*@dart\s*=\s*.+' ).firstMatch (source);
228+ final languageVersionComment = libraryUnit.languageVersionToken? .value ();
229+
230+ DartFormatter ? formatter;
231+ try {
232+ formatter = constructFormatter (
233+ // Try to use the actual version of the library if possible:
234+ // 1. to avoid any potential parse errors
235+ // 2. to preserve existing formatting in checked-in generated files in this repo when running on Dart 2
236+ languageVersion: libraryUnit.languageVersionToken? .asSemver () ??
237+ packageConfigLanguageVersion? .asSemver () ??
238+ // TODO use DartFormatter.latestLanguageVersion here once this package supports only Dart 3 and dart_style >=2.3.7
239+ semver.Version .parse (Platform .version
240+ .split (RegExp (r'\s' ))
241+ .first),
242+ );
243+ } catch (e, st) {
244+ // Formatting is not critical, so if it we can't construct a formatter, just skip it.
245+ log.warning ('Error constructing Dart formatter, skipping formatting step' , e, st);
246+ }
247+
227248 await _writePart (buildStep, outputId, outputs,
249+ formatter: formatter,
228250 nullSafetyCommentText: nullSafetyCommentText,
229- languageVersionComment: languageVersionCommentMatch ? . group ( 0 ) );
251+ languageVersionComment: languageVersionComment );
230252 } else {
231253 if (hasOutputPartDirective ()) {
232254 log.warning ('An over_react part directive was found in ${buildStep .inputId .path }, '
@@ -238,8 +260,6 @@ class OverReactBuilder extends Builder {
238260
239261 static final _headerLine = '// ' .padRight (77 , '*' );
240262
241- static final _formatter = DartFormatter ();
242-
243263 static CompilationUnit ? _tryParseCompilationUnit (String source, AssetId id) {
244264 final result = parseString (content: source, path: id.path, throwIfDiagnostics: false );
245265
@@ -264,8 +284,14 @@ class OverReactBuilder extends Builder {
264284 'invalid_use_of_visible_for_overriding_member' ,
265285 };
266286
267- static FutureOr <void > _writePart (BuildStep buildStep, AssetId outputId, Iterable <String > outputs,
268- {required String nullSafetyCommentText, String ? languageVersionComment}) async {
287+ static FutureOr <void > _writePart (
288+ BuildStep buildStep,
289+ AssetId outputId,
290+ Iterable <String > outputs, {
291+ required DartFormatter ? formatter,
292+ required String nullSafetyCommentText,
293+ String ? languageVersionComment,
294+ }) async {
269295 final partOf = "'${p .basename (buildStep .inputId .uri .toString ())}'" ;
270296
271297 final buffer = StringBuffer ();
@@ -298,15 +324,25 @@ class OverReactBuilder extends Builder {
298324
299325 var output = buffer.toString ();
300326 // Output the file even if formatting fails, so that it can be used to debug the issue.
301- try {
302- output = _formatter.format (buffer.toString ());
303- } catch (e, st) {
304- log.severe ('Error formatting generated code' , e, st);
327+ if (formatter != null ) {
328+ try {
329+ output = formatter.format (buffer.toString ());
330+ } catch (e, st) {
331+ log.severe ('Error formatting generated code' , e, st);
332+ }
305333 }
306334 await buildStep.writeAsString (outputId, output);
307335 }
308336}
309337
338+ extension on pc.LanguageVersion {
339+ semver.Version asSemver () => semver.Version (major, minor, 0 ); // There's no patch available on this version.
340+ }
341+
342+ extension on LanguageVersionToken {
343+ semver.Version asSemver () => semver.Version (major, minor, 0 ); // There's no patch available on this version.
344+ }
345+
310346extension on BuildStep {
311347 // Cache the result so we don't read and parse the package config for every file.
312348 //
0 commit comments