// 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 '../helpers/sourcemap_html_helper.dart'; main(List 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); } enum MappingState { initial('initial', 0, 1), mapped0('mapped0', 2, 3), mapped0Continued('mapped0continued', 2, 3), mapped1('mapped1', 4, 1), mapped1Continued('mapped1continued', 4, 1), unmapped('unmapped', 5, 1); 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]; } void generateHtml(String jsFileName, String jsMapFileName) { String jsFile = File(jsFileName).readAsStringSync(); String jsMapFile = File(jsMapFileName).readAsStringSync(); SingleMapping mapping = SingleMapping.fromJson(json.decode(jsMapFile)); StringBuffer output = StringBuffer(); output.write(''' ${escape(jsFileName)} / ${escape(jsMapFileName)}
     no mapping (yet)
      mapped
      mapping continued from previous line
     mapping off
''');

  MappingState state = MappingState.initial;
  TargetEntry? lastEntry;

  void write(String text, TargetEntry? entry) {
    output.write('');
    output.write(escape(text));
    output.write('');
  }

  int nextTargetLineIndex = 0;
  List 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('
'); File outputFile = File('out.js.map.html'); outputFile.writeAsStringSync(output.toString()); print('Output written to: ${outputFile.absolute.uri}'); }