blob: c2b71a3b77958e4328226cb343d685f42eb9797c [file] [log] [blame]
// Copyright (c) 2016, 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.
/// Loads a human-readable source map and outputs the source map file for it.
library save;
import 'dart:convert';
import 'dart:io';
import 'package:source_maps/source_maps.dart';
import '../helpers/lax_json.dart' as lazon;
void main(List<String> args) {
if (args.isEmpty) {
print('''
Usage: save <dir-containing 'out.js.map2'>
or: save <human-readable-source-map-file> [<source-map-file>]''');
exit(1);
}
File humanReadableSourceMapFile;
File? sourceMapFile;
if (args.length == 1 && Directory(args[0]).existsSync()) {
humanReadableSourceMapFile = File('${args[0]}/out.js.map2');
sourceMapFile = File('${args[0]}/out.js.map');
} else {
humanReadableSourceMapFile = File(args[0]);
if (args.length > 1) {
sourceMapFile = File(args[1]);
}
}
String humanReadableSourceMap = humanReadableSourceMapFile.readAsStringSync();
SingleMapping mapping = convertFromHumanReadableSourceMap(
humanReadableSourceMap,
);
if (sourceMapFile != null) {
sourceMapFile.writeAsStringSync(json.encoder.convert(mapping.toJson()));
} else {
print(new JsonEncoder.withIndent(' ').convert(mapping.toJson()));
}
}
SingleMapping convertFromHumanReadableSourceMap(String json) {
Map inputMap = lazon.decode(json);
Map urls = inputMap['sources'];
List<String?> sources = List.filled(urls.length, null);
urls.forEach((dynamic index, dynamic url) {
int i = int.parse(index);
assert(sources[i] == null);
sources[i] = url;
});
List lines = inputMap['lines'];
Map<String, int> names = <String, int>{};
Map<int, TargetLineEntry> lineEntryMap = {};
for (Map line in lines) {
String targetString = line['target']!;
String? sourceString = line['source'];
String? name = line['name'];
int? nameIndex;
if (name != null) {
nameIndex = names.putIfAbsent(name, () => names.length);
}
int? columnEnd;
int commaPos = targetString.indexOf(',');
final lineNo = int.parse(targetString.substring(0, commaPos)) - 1;
if (lineNo < 0) {
throw ArgumentError('target line must be > 0: $lineNo');
}
targetString = targetString.substring(commaPos + 1);
int dashPos = targetString.indexOf('-');
final columnStart = int.parse(targetString.substring(0, dashPos)) - 1;
if (columnStart < 0) {
throw ArgumentError('target column start must be > 0: $columnStart');
}
targetString = targetString.substring(dashPos + 1);
if (!targetString.isEmpty) {
columnEnd = int.parse(targetString) - 1;
if (columnEnd < 0) {
throw ArgumentError('target column end must be > 0: $columnEnd');
}
}
int? sourceUrlId;
int? sourceLine;
int? sourceColumn;
if (sourceString != null) {
int colonPos = sourceString.indexOf(':');
sourceUrlId = int.parse(sourceString.substring(0, colonPos));
if (sourceUrlId < 0) {
throw ArgumentError('source url id end must be > 0: $sourceUrlId');
} else if (sourceUrlId >= sources.length) {
throw ArgumentError(
'source url id end must be < ${sources.length}: $sourceUrlId',
);
}
sourceString = sourceString.substring(colonPos + 1);
int commaPos = sourceString.indexOf(',');
sourceLine = int.parse(sourceString.substring(0, commaPos)) - 1;
if (sourceLine < 0) {
throw ArgumentError('source line end must be > 0: $sourceLine');
}
sourceString = sourceString.substring(commaPos + 1);
sourceColumn = int.parse(sourceString) - 1;
if (sourceColumn < 0) {
throw ArgumentError('source column must be > 0: $sourceColumn');
}
}
TargetLineEntry lineEntry = lineEntryMap.putIfAbsent(
lineNo,
() => TargetLineEntry(lineNo, []),
);
lineEntry.entries.add(
TargetEntry(
columnStart,
sourceUrlId,
sourceLine,
sourceColumn,
nameIndex,
),
);
if (columnEnd != null) {
lineEntry.entries.add(TargetEntry(columnEnd));
}
}
List<TargetLineEntry> lineEntries = lineEntryMap.values.toList();
var outputMap = <String, dynamic>{
'version': 3,
'sourceRoot': inputMap['sourceRoot'],
'file': inputMap['file'],
'sources': sources,
'names': names.keys.toList(),
'mappings': '',
};
SingleMapping mapping = SingleMapping.fromJson(outputMap);
mapping.lines.addAll(lineEntries);
return mapping;
}