Treat "package:" URLs as absolute. (#25)
Closes #22
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67c849c..b29d2ab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
## 1.4.2
+* Treat `package:` URLs as absolute.
+
* Normalize `c:\foo\.` to `c:\foo`.
## 1.4.1
diff --git a/lib/src/style/url.dart b/lib/src/style/url.dart
index f4bab64..2e29aa7 100644
--- a/lib/src/style/url.dart
+++ b/lib/src/style/url.dart
@@ -41,19 +41,29 @@
if (path.isEmpty) return 0;
if (isSeparator(path.codeUnitAt(0))) return 1;
+ for (var i = 0; i < path.length; i++) {
+ var codeUnit = path.codeUnitAt(i);
+ if (isSeparator(codeUnit)) return 0;
+ if (codeUnit == chars.COLON) {
+ if (i == 0) return 0;
+
+ // The root part is up until the next '/', or the full path. Skip ':'
+ // (and '//' if it exists) and search for '/' after that.
+ if (path.startsWith('//', i + 1)) i += 3;
+ var index = path.indexOf('/', i);
+ if (index <= 0) return path.length;
+
+ // file: URLs sometimes consider Windows drive letters part of the root.
+ // See https://url.spec.whatwg.org/#file-slash-state.
+ if (!withDrive || path.length < index + 3) return index;
+ if (!path.startsWith('file://')) return index;
+ if (!isDriveLetter(path, index + 1)) return index;
+ return path.length == index + 3 ? index + 3 : index + 4;
+ }
+ }
+
var index = path.indexOf("/");
if (index > 0 && path.startsWith('://', index - 1)) {
- // The root part is up until the next '/', or the full path. Skip
- // '://' and search for '/' after that.
- index = path.indexOf('/', index + 2);
- if (index <= 0) return path.length;
-
- // file: URLs sometimes consider Windows drive letters part of the root.
- // See https://url.spec.whatwg.org/#file-slash-state.
- if (!withDrive || path.length < index + 3) return index;
- if (!path.startsWith('file://')) return index;
- if (!isDriveLetter(path, index + 1)) return index;
- return path.length == index + 3 ? index + 3 : index + 4;
}
return 0;
}
diff --git a/pubspec.yaml b/pubspec.yaml
index ff101d6..2c90e1c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: path
-version: 1.4.2-dev
+version: 1.4.2
author: Dart Team <misc@dartlang.org>
description: >
A string-based path manipulation library. All of the path operations you know
diff --git a/test/url_test.dart b/test/url_test.dart
index e8f3413..b8f4e0f 100644
--- a/test/url_test.dart
+++ b/test/url_test.dart
@@ -40,6 +40,8 @@
expect(context.rootPrefix('file://'), 'file://');
expect(context.rootPrefix('/'), '/');
expect(context.rootPrefix('foo/bar://'), '');
+ expect(context.rootPrefix('package:foo/bar.dart'), 'package:foo');
+ expect(context.rootPrefix('foo/bar:baz/qux'), '');
});
test('dirname', () {
@@ -136,8 +138,10 @@
expect(context.isAbsolute('~'), false);
expect(context.isAbsolute('.'), false);
expect(context.isAbsolute('../a'), false);
- expect(context.isAbsolute('C:/a'), false);
- expect(context.isAbsolute(r'C:\a'), false);
+ expect(context.isAbsolute('C:/a'), true);
+ expect(context.isAbsolute(r'C:\a'), true);
+ expect(context.isAbsolute('package:foo/bar.dart'), true);
+ expect(context.isAbsolute('foo/bar:baz/qux'), false);
expect(context.isAbsolute(r'\\a'), false);
});
@@ -159,8 +163,10 @@
expect(context.isRelative('~'), true);
expect(context.isRelative('.'), true);
expect(context.isRelative('../a'), true);
- expect(context.isRelative('C:/a'), true);
- expect(context.isRelative(r'C:\a'), true);
+ expect(context.isRelative('C:/a'), false);
+ expect(context.isRelative(r'C:\a'), false);
+ expect(context.isRelative(r'package:foo/bar.dart'), false);
+ expect(context.isRelative('foo/bar:baz/qux'), true);
expect(context.isRelative(r'\\a'), true);
});
@@ -184,6 +190,8 @@
expect(context.isRootRelative('../a'), false);
expect(context.isRootRelative('C:/a'), false);
expect(context.isRootRelative(r'C:\a'), false);
+ expect(context.isRootRelative(r'package:foo/bar.dart'), false);
+ expect(context.isRootRelative('foo/bar:baz/qux'), false);
expect(context.isRootRelative(r'\\a'), false);
});
@@ -216,7 +224,9 @@
'a', 'http://google.com/b', 'http://dartlang.org/c', 'd'),
'http://dartlang.org/c/d');
expect(context.join('a', '/b', '/c', 'd'), '/c/d');
- expect(context.join('a', r'c:\b', 'c', 'd'), r'a/c:\b/c/d');
+ expect(context.join('a', r'c:\b', 'c', 'd'), r'c:\b/c/d');
+ expect(context.join('a', 'package:foo/bar', 'c', 'd'),
+ r'package:foo/bar/c/d');
expect(context.join('a', r'\\b', 'c', 'd'), r'a/\\b/c/d');
});
@@ -225,6 +235,8 @@
'http://dartlang.org/b/c');
expect(context.join('file://', 'a', '/b', 'c'), 'file:///b/c');
expect(context.join('file://', 'a', '/b', 'c', '/d'), 'file:///d');
+ expect(context.join('package:foo/bar.dart', '/baz.dart'),
+ 'package:foo/baz.dart');
});
test('ignores trailing nulls', () {
@@ -294,7 +306,9 @@
'd'
]), 'http://dartlang.org/c/d');
expect(context.joinAll(['a', '/b', '/c', 'd']), '/c/d');
- expect(context.joinAll(['a', r'c:\b', 'c', 'd']), r'a/c:\b/c/d');
+ expect(context.joinAll(['a', r'c:\b', 'c', 'd']), r'c:\b/c/d');
+ expect(context.joinAll(['a', 'package:foo/bar', 'c', 'd']),
+ r'package:foo/bar/c/d');
expect(context.joinAll(['a', r'\\b', 'c', 'd']), r'a/\\b/c/d');
});
@@ -405,8 +419,9 @@
'http://dartlang.org/a');
expect(context.normalize('file:///../../../a'), 'file:///a');
expect(context.normalize('/../../../a'), '/a');
- expect(context.normalize('c:/..'), '.');
- expect(context.normalize('A:/../../..'), '../..');
+ expect(context.normalize('c:/..'), 'c:');
+ expect(context.normalize('package:foo/..'), 'package:foo');
+ expect(context.normalize('A:/../../..'), 'A:');
expect(context.normalize('a/..'), '.');
expect(context.normalize('a/b/..'), 'a');
expect(context.normalize('a/../b'), 'b');
@@ -430,7 +445,8 @@
expect(context.normalize('a/..'), '.');
expect(context.normalize('../a'), '../a');
expect(context.normalize('/../a'), '/a');
- expect(context.normalize('c:/../a'), 'a');
+ expect(context.normalize('c:/../a'), 'c:/a');
+ expect(context.normalize('package:foo/../a'), 'package:foo/a');
expect(context.normalize('/../a'), '/a');
expect(context.normalize('a/b/..'), 'a');
expect(context.normalize('../a/b/..'), '../a');
@@ -778,8 +794,7 @@
test('ignores parts before an absolute path', () {
expect(context.absolute('a', '/b', '/c', 'd'), 'http://dartlang.org/c/d');
expect(context.absolute('a', '/b', 'file:///c', 'd'), 'file:///c/d');
- expect(context.absolute('a', r'c:\b', 'c', 'd'),
- r'http://dartlang.org/root/path/a/c:\b/c/d');
+ expect(context.absolute('a', r'c:\b', 'c', 'd'), r'c:\b/c/d');
expect(context.absolute('a', r'\\b', 'c', 'd'),
r'http://dartlang.org/root/path/a/\\b/c/d');
});