| Index: tests/compiler/dart2js/sourcemaps/sourcemap_visualizer.dart
|
| diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_visualizer.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_visualizer.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3b6a96dd747c1b855c4ae53e00da249aef4c6863
|
| --- /dev/null
|
| +++ b/tests/compiler/dart2js/sourcemaps/sourcemap_visualizer.dart
|
| @@ -0,0 +1,194 @@
|
| +// 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.
|
| +
|
| +/// Tool for visualizing the source mapped parts of a generated JS file.
|
| +
|
| +import 'dart:convert';
|
| +import 'dart:io';
|
| +import 'package:source_maps/source_maps.dart';
|
| +import 'sourcemap_html_helper.dart';
|
| +
|
| +main(List<String> args) {
|
| + String jsFileName = 'out.js';
|
| + if (args.length > 0) {
|
| + jsFileName = args[0];
|
| + }
|
| + String jsMapFileName = '$jsFileName.map';
|
| + if (args.length > 1) {
|
| + jsMapFileName = args[1];
|
| + }
|
| + generateHtml(jsFileName, jsMapFileName);
|
| +}
|
| +
|
| +class MappingState {
|
| + final String cssClass;
|
| + final int _continuedState;
|
| + final int _nextState;
|
| +
|
| + const MappingState(this.cssClass, this._continuedState, this._nextState);
|
| +
|
| + MappingState get continuedState => values[_continuedState];
|
| +
|
| + MappingState get nextState => values[_nextState];
|
| +
|
| + static const MappingState INITIAL = const MappingState('initial', 0, 1);
|
| + static const MappingState MAPPED0 = const MappingState('mapped0', 2, 3);
|
| + static const MappingState MAPPED0_CONTINUED =
|
| + const MappingState('mapped0continued', 2, 3);
|
| + static const MappingState MAPPED1 = const MappingState('mapped1', 4, 1);
|
| + static const MappingState MAPPED1_CONTINUED =
|
| + const MappingState('mapped1continued', 4, 1);
|
| + static const MappingState UNMAPPED = const MappingState('unmapped', 5, 1);
|
| +
|
| + static const List<MappingState> values = const <MappingState>[
|
| + INITIAL,
|
| + MAPPED0,
|
| + MAPPED0_CONTINUED,
|
| + MAPPED1,
|
| + MAPPED1_CONTINUED,
|
| + UNMAPPED
|
| + ];
|
| +}
|
| +
|
| +void generateHtml(String jsFileName, String jsMapFileName) {
|
| + String jsFile = new File(jsFileName).readAsStringSync();
|
| + String jsMapFile = new File(jsMapFileName).readAsStringSync();
|
| + SingleMapping mapping = new SingleMapping.fromJson(JSON.decode(jsMapFile));
|
| + StringBuffer output = new StringBuffer();
|
| + output.write('''
|
| +<html>
|
| + <head>
|
| + <title>${escape(jsFileName)} / ${escape(jsMapFileName)}</title>
|
| + <style type="text/css">
|
| + .initial{
|
| + background-color: #FFFFFF;
|
| + }
|
| + .mapped0 {
|
| + background-color: #E0E0C0;
|
| + }
|
| + .mapped0continued {
|
| + background-color: #F8F8D8;
|
| + }
|
| + .mapped1 {
|
| + background-color: #C0E0E0;
|
| + }
|
| + .mapped1continued {
|
| + background-color: #D8F8F8;
|
| + }
|
| + .unmapped {
|
| + background-color: #E0E0E0;
|
| + }
|
| + .code {
|
| + font-family: monospace;
|
| + white-space: pre;
|
| + font-size: smaller;
|
| + }
|
| + .lineNumber {
|
| + color: #C0C0C0;
|
| + font-size: small;
|
| + }
|
| + .legend {
|
| + position: fixed;
|
| + top: 5px;
|
| + right: 5px;
|
| + border: 1px solid black;
|
| + padding: 5px;
|
| + background-color: #F0F0F0;
|
| + }
|
| + .box {
|
| + border: 1px solid grey;
|
| + }
|
| + </style>
|
| + </head>
|
| + <body>
|
| + <div class="legend">
|
| + <span class="initial"> </span> no mapping (yet)<br/>
|
| + <span class="mapped0"> </span>
|
| + <span class="mapped1"> </span> mapped<br/>
|
| + <span class="mapped0continued"> </span>
|
| + <span class="mapped1continued"> </span> mapping
|
| + continued from previous line<br/>
|
| + <span class="unmapped"> </span> mapping off<br/>
|
| + </div>
|
| + <pre class="code">
|
| +''');
|
| +
|
| + MappingState state = MappingState.INITIAL;
|
| + TargetEntry lastEntry;
|
| +
|
| + void write(String text, TargetEntry entry) {
|
| + output.write('<span class="${state.cssClass}"');
|
| + String prefix = '';
|
| + if (entry == lastEntry) {
|
| + prefix = 'continued: ';
|
| + }
|
| + lastEntry = entry;
|
| + if (lastEntry != null) {
|
| + if (lastEntry.sourceUrlId != null) {
|
| + output.write(' title="$prefix');
|
| + output.write(escape(mapping.urls[lastEntry.sourceUrlId]));
|
| + output.write(
|
| + ':${lastEntry.sourceLine + 1}:${lastEntry.sourceColumn + 1}');
|
| + if (lastEntry.sourceNameId != null) {
|
| + output.write(' (');
|
| + output.write(escape(mapping.names[lastEntry.sourceNameId]));
|
| + output.write(')');
|
| + }
|
| + output.write('"');
|
| + } else {
|
| + output.write(' title="unmapped"');
|
| + }
|
| + }
|
| + output.write('>');
|
| + output.write(escape(text));
|
| + output.write('</span>');
|
| + }
|
| +
|
| + int nextTargetLineIndex = 0;
|
| + List<String> lines = jsFile.split('\n');
|
| + int lineNoWidth = '${lines.length}'.length;
|
| + for (int lineNo = 0; lineNo < lines.length; lineNo++) {
|
| + output.write(lineNumber(lineNo, width: lineNoWidth));
|
| + String line = lines[lineNo];
|
| + TargetLineEntry targetLineEntry;
|
| + while (nextTargetLineIndex < mapping.lines.length) {
|
| + TargetLineEntry entry = mapping.lines[nextTargetLineIndex];
|
| + if (entry.line == lineNo) {
|
| + targetLineEntry = entry;
|
| + nextTargetLineIndex++;
|
| + break;
|
| + } else if (entry.line > lineNo) {
|
| + break;
|
| + } else {
|
| + nextTargetLineIndex++;
|
| + }
|
| + }
|
| + if (targetLineEntry != null) {
|
| + int columnNo = 0;
|
| + for (int index = 0; index < targetLineEntry.entries.length; index++) {
|
| + TargetEntry entry = targetLineEntry.entries[index];
|
| + if (entry.column > columnNo) {
|
| + write(line.substring(columnNo, entry.column), lastEntry);
|
| + columnNo = entry.column;
|
| + }
|
| + state =
|
| + entry.sourceUrlId != null ? state.nextState : MappingState.UNMAPPED;
|
| + int end;
|
| + if (index + 1 < targetLineEntry.entries.length) {
|
| + end = targetLineEntry.entries[index + 1].column;
|
| + } else {
|
| + end = line.length;
|
| + }
|
| + write(line.substring(entry.column, end), entry);
|
| + columnNo = end;
|
| + }
|
| + } else {
|
| + write(line, lastEntry);
|
| + }
|
| + output.write('\n');
|
| + state = state.continuedState;
|
| + }
|
| + output.write('</pre></body></html>');
|
| + new File('out.js.map.html').writeAsStringSync(output.toString());
|
| +}
|
|
|