blob: 93405a7fb999a4431c848c5aa0ca31b2bac7d189 [file] [log] [blame]
// Copyright (c) 2019, 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.
import 'package:path/path.dart' as p;
/// The URI for a particular Dart file, able to canonicalize from various
/// different representations.
class DartUri {
/// The canonical web server path part of the URI.
///
/// This is a relative path, which can be used to fetch the corresponding file
/// from the server. For example, 'hello_world/main.dart' or
/// 'packages/path/src/utils.dart'.
final String serverPath;
/// Accepts various forms of URI and can convert between forms.
///
/// The accepted forms are:
///
/// - package:packageName/pathUnderLib/file.dart
/// - org-dartlang-app:///prefix/path/file.dart, where prefix is ignored.
/// e.g. org-dartlang-app:example/hello_world/main.dart,
/// - /packages/packageName/foo.dart, the web server form of a package URI,
/// e.g. /packages/path/src/utils.dart
/// - /path/foo.dart or path/foo.dart, e.g. /hello_world/web/main.dart, where
/// path is a web server path and so relative to the directory being
/// served, not to the package.
///
/// The optional [serverUri] is a temporary workaround for a bug with construction.
/// Older SDKs (before D24) gave us a path that didn't include the full path,
/// e.g. main.dart rather than hello_world/main.dart and src/path.dart rather than
/// packages/path/src/path.dart. The optional [serverUri] is the full URI of the
/// JS script. The dirname of that path should give us the missing prefix.
factory DartUri(String uri, [String serverUri]) {
// TODO(401): Remove serverUri after D24 is stable.
if (uri.startsWith('package:')) return DartUri._fromPackageUri(uri);
if (uri.startsWith('org-dartlang-app:')) return DartUri._fromAppUri(uri);
if (uri.startsWith('/packages/')) return DartUri._fromServerPath(uri);
if (uri.startsWith('/')) return DartUri._fromServerPath(uri);
if (uri.startsWith('http:') || uri.startsWith('https:')) {
return DartUri(Uri.parse(uri).path);
}
// Work around short paths if we have been provided the context.
if (serverUri != null) {
var path = Uri.parse(serverUri).path;
var dir = p.dirname(path);
return DartUri._fromServerPath(p.join(dir, uri));
}
throw FormatException('Unsupported URI form', uri);
}
/// Construct from a package: URI
factory DartUri._fromPackageUri(String uri) {
return DartUri._('packages/${uri.substring("package:".length)}');
}
/// Construct from an org-dartlang-app: URI.
factory DartUri._fromAppUri(String uri) {
// We ignore the first segment of the path, which is the root
// from which we're serving.
// TODO: To be able to convert to an org-dartlang-app: URI we will
// need to know the root - possibly keep it as a static?
return DartUri._(Uri.parse(uri).pathSegments.skip(1).join('/').toString());
}
DartUri._(this.serverPath);
/// Construct from a path, relative to the directory being served.
factory DartUri._fromServerPath(String uri) {
uri = uri[0] == '.' ? uri.substring(1) : uri;
uri = uri[0] == '/' ? uri.substring(1) : uri;
return DartUri._(uri);
}
}