From 3db0ae1dacbb6e03edbee4e65ad3e804ce26b904 Mon Sep 17 00:00:00 2001 From: Tim Blasi Date: Wed, 5 Aug 2015 17:39:37 -0700 Subject: [PATCH] refactor(dart/transform): Show friendly messages for transform failures Previously, the error messages coming out of the Dart transformer were opaque when those errors came from the analyzer (for example, analyzer parse errors). Log more useful errors when they are caught by the transform code. --- .../src/transform/common/logging.dart | 47 +++++++++++++++++-- .../transform/directive_linker/all_tests.dart | 4 +- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/modules/angular2/src/transform/common/logging.dart b/modules/angular2/src/transform/common/logging.dart index 20e51b2730..9ad1e9aa32 100644 --- a/modules/angular2/src/transform/common/logging.dart +++ b/modules/angular2/src/transform/common/logging.dart @@ -1,6 +1,8 @@ library angular2.transform.common.logging; import 'dart:async'; + +import 'package:analyzer/analyzer.dart'; import 'package:barback/barback.dart'; import 'package:code_transformers/messages/build_logger.dart'; import 'package:source_span/source_span.dart'; @@ -11,11 +13,36 @@ typedef _SimpleCallback(); final _key = #loggingZonedLoggerKey; /// Executes {@link fn} inside a new {@link Zone} with its own logger. -dynamic initZoned(Transform t, _SimpleCallback fn) => +Future initZoned(Transform t, _SimpleCallback fn) => setZoned(new BuildLogger(t), fn); -dynamic setZoned(BuildLogger logger, _SimpleCallback fn) { - return runZoned(fn, zoneValues: {_key: logger}); +Future setZoned(BuildLogger logger, _SimpleCallback fn) async { + return runZoned(() async { + try { + await fn(); + } on AnalyzerError catch (e) { + // Do not worry about printing the stack trace, barback will handle that + // on its own when it catches the rethrown exception. + logger + .error(' Failed with ${e.runtimeType}\n${_friendlyError(e.error)}'); + rethrow; + } on AnalyzerErrorGroup catch (eGroup) { + // See above re: stack trace. + var numErrors = eGroup.errors.length; + if (numErrors == 1) { + logger.error(_friendlyError(eGroup.errors[0].error)); + } else { + var buf = new StringBuffer(); + buf.writeln(' Failed with ${numErrors} errors'); + for (var i = 0; i < numErrors; ++i) { + buf.writeln( + 'Error ${i + 1}: ${_friendlyError(eGroup.errors[i].error)}'); + } + logger.error('$buf'); + } + rethrow; + } + }, zoneValues: {_key: logger}); } /// The logger for the current {@link Zone}. @@ -59,3 +86,17 @@ class PrintLoggerError extends Error { 'Span: ${Error.safeToString(span)}.'; } } + +/// Generate a human-readable error message from `error`. +String _friendlyError(AnalysisError error) { + if (error.source != null) { + var file = + new SourceFile(error.source.contents.data, url: error.source.fullName); + + return file + .span(error.offset, error.offset + error.length) + .message(error.message, color: false); + } else { + return ': ${error.message}'; + } +} diff --git a/modules/angular2/test/transform/directive_linker/all_tests.dart b/modules/angular2/test/transform/directive_linker/all_tests.dart index 4a3e122424..378ef55ba2 100644 --- a/modules/angular2/test/transform/directive_linker/all_tests.dart +++ b/modules/angular2/test/transform/directive_linker/all_tests.dart @@ -25,7 +25,7 @@ void allTests() { inputPath = 'directive_linker/simple_files/$inputPath'; var actual = formatter .format(await linkNgDeps(reader, new AssetId('a', inputPath))); - expect(actual).toEqual(expected); + expect(actual).toEqual(formatter.format(expected)); } }); @@ -41,7 +41,7 @@ void allTests() { inputPath = 'directive_linker/simple_export_files/$inputPath'; var actual = formatter .format(await linkNgDeps(reader, new AssetId('a', inputPath))); - expect(actual).toEqual(expected); + expect(actual).toEqual(formatter.format(expected)); } }); }