| // 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. | |
| library _fe_analyzer_shared.util.relativize; | |
| import 'dart:math'; | |
| /// Detect if we're on Windows without importing `dart:io`. | |
| bool isWindows = | |
| new Uri.directory("C:\\").path == | |
| new Uri.directory("C:\\", windows: true).path; | |
| String relativizeUri(Uri base, Uri uri, bool isWindows) { | |
| bool equalsNCS(String a, String b) { | |
| return a.toLowerCase() == b.toLowerCase(); | |
| } | |
| if (!equalsNCS(base.scheme, uri.scheme) || | |
| equalsNCS(base.scheme, 'dart') || | |
| equalsNCS(base.scheme, 'package')) { | |
| return uri.toString(); | |
| } | |
| if (!equalsNCS(base.scheme, 'file')) { | |
| isWindows = false; | |
| } | |
| String normalize(String path) { | |
| if (isWindows) { | |
| return path.toLowerCase(); | |
| } else { | |
| return path; | |
| } | |
| } | |
| if (base.userInfo == uri.userInfo && | |
| equalsNCS(base.host, uri.host) && | |
| base.port == uri.port && | |
| uri.query == "" && | |
| uri.fragment == "") { | |
| if (normalize(uri.path).startsWith(normalize(base.path))) { | |
| return uri.path.substring(base.path.lastIndexOf('/') + 1); | |
| } | |
| if (!base.path.startsWith('/') || !uri.path.startsWith('/')) { | |
| return uri.toString(); | |
| } | |
| List<String> uriParts = uri.path.split('/'); | |
| List<String> baseParts = base.path.split('/'); | |
| int common = 0; | |
| int length = min(uriParts.length, baseParts.length); | |
| while (common < length && | |
| normalize(uriParts[common]) == normalize(baseParts[common])) { | |
| common++; | |
| } | |
| if (common == 1 || (isWindows && common == 2)) { | |
| // The first part will always be an empty string because the | |
| // paths are absolute. On Windows, we must also consider drive | |
| // letters or hostnames. | |
| if (baseParts.length > common + 1) { | |
| // Avoid using '..' to go to the root, unless we are already there. | |
| return uri.path; | |
| } | |
| } | |
| StringBuffer sb = new StringBuffer(); | |
| for (int i = common + 1; i < baseParts.length; i++) { | |
| sb.write('../'); | |
| } | |
| for (int i = common; i < uriParts.length - 1; i++) { | |
| sb.write('${uriParts[i]}/'); | |
| } | |
| sb.write('${uriParts.last}'); | |
| return sb.toString(); | |
| } | |
| return uri.toString(); | |
| } |