[dartdevc] DDK now outputs relative paths in source maps

Bug: https://buganizer.corp.google.com/issues/133784498
Change-Id: Ifbaae661ac401d0a935a100fbbb7fa2e42325abc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105703
Commit-Queue: Mark Zhou <markzipan@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 397f0ed..0388456 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -344,21 +344,28 @@
 
 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
 /// and returns the new map.  Relative paths are in terms of URIs ('/'), not
-/// local OS paths (e.g., windows '\').
+/// local OS paths (e.g., windows '\'). Sources with a multi-root scheme
+/// matching [multiRootScheme] are adjusted to be relative to
+/// [multiRootOutputPath].
 // TODO(jmesserly): find a new home for this.
 Map placeSourceMap(Map sourceMap, String sourceMapPath,
-    Map<String, String> bazelMappings, String customScheme) {
+    Map<String, String> bazelMappings, String multiRootScheme,
+    {String multiRootOutputPath}) {
   var map = Map.from(sourceMap);
   // Convert to a local file path if it's not.
   sourceMapPath = path.fromUri(sourcePathToUri(sourceMapPath));
   var sourceMapDir = path.dirname(path.absolute(sourceMapPath));
   var list = (map['sources'] as List).toList();
-  map['sources'] = list;
 
   String makeRelative(String sourcePath) {
     var uri = sourcePathToUri(sourcePath);
     var scheme = uri.scheme;
-    if (scheme == 'dart' || scheme == 'package' || scheme == customScheme) {
+    if (scheme == 'dart' || scheme == 'package' || scheme == multiRootScheme) {
+      if (scheme == multiRootScheme) {
+        var multiRootPath = '$multiRootOutputPath${uri.path}';
+        multiRootPath = path.relative(multiRootPath, from: sourceMapDir);
+        return multiRootPath;
+      }
       return sourcePath;
     }
 
@@ -379,6 +386,7 @@
   for (int i = 0; i < list.length; i++) {
     list[i] = makeRelative(list[i] as String);
   }
+  map['sources'] = list;
   map['file'] = makeRelative(map['file'] as String);
   return map;
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 364981a..2e897f0 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -130,13 +130,14 @@
   // the correct location and keeps the real file location hidden from the
   // front end.
   var multiRootScheme = argResults['multi-root-scheme'] as String;
+  var multiRootPaths = (argResults['multi-root'] as Iterable<String>)
+      .map(Uri.base.resolve)
+      .toList();
+  var multiRootOutputPath =
+      _longestPrefixingPath(path.absolute(output), multiRootPaths);
 
   var fileSystem = MultiRootFileSystem(
-      multiRootScheme,
-      (argResults['multi-root'] as Iterable<String>)
-          .map(Uri.base.resolve)
-          .toList(),
-      fe.StandardFileSystem.instance);
+      multiRootScheme, multiRootPaths, fe.StandardFileSystem.instance);
 
   Uri toCustomUri(Uri uri) {
     if (uri.scheme == '') {
@@ -354,7 +355,8 @@
       jsUrl: path.toUri(output).toString(),
       mapUrl: path.toUri(output + '.map').toString(),
       bazelMapping: options.bazelMapping,
-      customScheme: multiRootScheme);
+      customScheme: multiRootScheme,
+      multiRootOutputPath: multiRootOutputPath);
 
   outFiles.add(file.writeAsString(jsCode.code));
   if (jsCode.sourceMap != null) {
@@ -390,7 +392,8 @@
     String jsUrl,
     String mapUrl,
     Map<String, String> bazelMapping,
-    String customScheme}) {
+    String customScheme,
+    String multiRootOutputPath}) {
   var opts = JS.JavaScriptPrintingOptions(
       allowKeywordsInProperties: true, allowSingleLineIfStatements: true);
   JS.SimpleJavaScriptPrintingContext printer;
@@ -409,7 +412,8 @@
   Map builtMap;
   if (buildSourceMap && sourceMap != null) {
     builtMap = placeSourceMap(
-        sourceMap.build(jsUrl), mapUrl, bazelMapping, customScheme);
+        sourceMap.build(jsUrl), mapUrl, bazelMapping, customScheme,
+        multiRootOutputPath: multiRootOutputPath);
     var jsDir = path.dirname(path.fromUri(jsUrl));
     var relative = path.relative(path.fromUri(mapUrl), from: jsDir);
     var relativeMapUrl = path.toUri(relative).toString();
@@ -505,3 +509,14 @@
     dir = parent;
   }
 }
+
+/// Inputs must be absolute paths. Returns null if no prefixing path is found.
+String _longestPrefixingPath(String basePath, List<Uri> prefixingPaths) {
+  return prefixingPaths.fold(null, (String previousValue, Uri element) {
+    if (basePath.startsWith(element.path) &&
+        (previousValue == null || previousValue.length < element.path.length)) {
+      return element.path;
+    }
+    return previousValue;
+  });
+}