Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(313)

Unified Diff: pkg/dev_compiler/web/stack_trace_mapper.dart

Issue 2735303002: Make all DDC internal stack traces apply source maps. (Closed)
Patch Set: Make all DDC internal stack traces apply source maps. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/private/js_helper.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/dev_compiler/web/stack_trace_mapper.dart
diff --git a/pkg/dev_compiler/web/stack_trace_mapper.dart b/pkg/dev_compiler/web/stack_trace_mapper.dart
new file mode 100644
index 0000000000000000000000000000000000000000..557e6fd6ddf1e4db0aaf3e67a442de81140b8549
--- /dev/null
+++ b/pkg/dev_compiler/web/stack_trace_mapper.dart
@@ -0,0 +1,134 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+/// Standalone utility that manages loading source maps for all Dart scripts
+/// on the page compiled with DDC.
+///
+/// Example JavaScript usage:
+/// $dartStackTraceUtility.addLoadedListener(function() {
+/// // All Dart source maps are now loaded. It is now safe to start your
+/// // Dart application compiled with DDC.
+/// dart_library.start('your_dart_application');
+/// })
+///
+/// If $dartStackTraceUtility is set, the dart:core StackTrace class calls
+/// $dartStackTraceUtility.mapper(someJSStackTrace)
+/// to apply source maps.
+///
+/// This utility can be compiled to JavaScript using Dart2JS while the rest
+/// of the application is compiled with DDC or could be compiled with DDC.
+
+@JS()
+library stack_trace_mapper;
+
+import 'dart:async';
+import 'dart:html';
+
+import 'package:js/js.dart';
+import 'package:path/path.dart' as path;
+import 'package:source_map_stack_trace/source_map_stack_trace.dart';
+import 'package:source_maps/source_maps.dart';
+import 'package:source_span/source_span.dart';
+import 'package:stack_trace/stack_trace.dart';
+
+typedef void ReadyCallback();
+
+/// Global object DDC uses to see if a stack trace utility has been registered.
+@JS(r'$dartStackTraceUtility')
+external set dartStackTraceUtility(DartStackTraceUtility value);
+
+typedef String StackTraceMapper(String stackTrace);
+typedef dynamic LoadSourceMaps(List<String> scripts, ReadyCallback callback);
+
+@JS()
+@anonymous
+class DartStackTraceUtility {
+ external factory DartStackTraceUtility(
+ {StackTraceMapper mapper, LoadSourceMaps loadSourceMaps});
+}
+
+/// Source mapping that is waits to parse source maps until they match the uri
+/// of a requested source map.
+///
+/// This improves startup performance compared to using MappingBundle directly.
+/// The unparsed data for the source maps must still be loaded before
+/// LazyMapping is used.
+class LazyMapping extends Mapping {
+ MappingBundle _bundle = new MappingBundle();
+
+ /// Map from url to unparsed source map.
+ Map<String, String> _sourceMaps;
+
+ LazyMapping(this._sourceMaps) {}
+
+ List toJson() => _bundle.toJson();
+
+ SourceMapSpan spanFor(int line, int column,
+ {Map<String, SourceFile> files, String uri}) {
+ if (uri == null) {
+ throw new ArgumentError.notNull('uri');
+ }
+ var rawMap = _sourceMaps[uri];
+
+ if (rawMap != null && rawMap.isNotEmpty && !_bundle.containsMapping(uri)) {
+ SingleMapping mapping = parse(rawMap);
+ mapping
+ ..targetUrl = uri
+ ..sourceRoot = '${path.dirname(uri)}/';
+ _bundle.addMapping(mapping);
+ }
+
+ return _bundle.spanFor(line, column, files: files, uri: uri);
+ }
+}
+
+String _toSourceMapLocation(String url) {
+ // The url may have cache busting query parameters which we need to maintain
+ // in the source map url.
+ // For example:
+ // http://localhost/foo.js?cachebusting=23419
+ // Should get source map
+ // http://localhost/foo.js.map?cachebusting=23419
+ var uri = Uri.parse(url);
+ return uri.replace(path: '${uri.path}.map').toString();
+}
+
+/// Load a source map for the specified url.
+///
+/// Returns a null string rather than reporting an error if the file cannot be
+/// found as we don't want to throw errors if a few source maps are missing.
+Future<String> loadSourceMap(String url) async {
+ try {
+ return await HttpRequest.getString(_toSourceMapLocation(url));
+ } catch (e) {
+ return null;
+ }
+}
+
+LazyMapping _mapping;
+
+String mapper(String rawStackTrace) {
+ if (_mapping == null) {
+ // This should not happen if the user has waited for the ReadyCallback
+ // to start the application.
+ throw new StateError('Source maps are not done loading.');
+ }
+ return mapStackTrace(_mapping, new Trace.parse(rawStackTrace)).toString();
+}
+
+Future<Null> loadSourceMaps(
+ List<String> scripts, ReadyCallback callback) async {
+ List<Future<String>> sourceMapFutures =
+ scripts.map((script) => loadSourceMap(script)).toList();
+ List<String> sourceMaps = await Future.wait(sourceMapFutures);
+ _mapping = new LazyMapping(new Map.fromIterables(scripts, sourceMaps));
+ callback();
+}
+
+main() {
+ // Register with DDC.
+ dartStackTraceUtility = new DartStackTraceUtility(
+ mapper: allowInterop(mapper),
+ loadSourceMaps: allowInterop(loadSourceMaps));
+}
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/private/js_helper.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698