Index: mojo/public/dart/third_party/path/lib/src/parsed_path.dart |
diff --git a/mojo/public/dart/third_party/path/lib/src/parsed_path.dart b/mojo/public/dart/third_party/path/lib/src/parsed_path.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d37e2d396211dcc195d103c8e7df1326c220f60a |
--- /dev/null |
+++ b/mojo/public/dart/third_party/path/lib/src/parsed_path.dart |
@@ -0,0 +1,183 @@ |
+// Copyright (c) 2013, 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 path.parsed_path; |
+ |
+import 'internal_style.dart'; |
+import 'style.dart'; |
+ |
+class ParsedPath { |
+ /// The [InternalStyle] that was used to parse this path. |
+ InternalStyle style; |
+ |
+ /// The absolute root portion of the path, or `null` if the path is relative. |
+ /// On POSIX systems, this will be `null` or "/". On Windows, it can be |
+ /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive |
+ /// letters. |
+ String root; |
+ |
+ /// Whether this path is root-relative. |
+ /// |
+ /// See [Context.isRootRelative]. |
+ bool isRootRelative; |
+ |
+ /// The path-separated parts of the path. All but the last will be |
+ /// directories. |
+ List<String> parts; |
+ |
+ /// The path separators preceding each part. |
+ /// |
+ /// The first one will be an empty string unless the root requires a separator |
+ /// between it and the path. The last one will be an empty string unless the |
+ /// path ends with a trailing separator. |
+ List<String> separators; |
+ |
+ /// The file extension of the last non-empty part, or "" if it doesn't have |
+ /// one. |
+ String get extension => _splitExtension()[1]; |
+ |
+ /// `true` if this is an absolute path. |
+ bool get isAbsolute => root != null; |
+ |
+ factory ParsedPath.parse(String path, InternalStyle style) { |
+ // Remove the root prefix, if any. |
+ var root = style.getRoot(path); |
+ var isRootRelative = style.isRootRelative(path); |
+ if (root != null) path = path.substring(root.length); |
+ |
+ // Split the parts on path separators. |
+ var parts = <String>[]; |
+ var separators = <String>[]; |
+ |
+ var start = 0; |
+ |
+ if (path.isNotEmpty && style.isSeparator(path.codeUnitAt(0))) { |
+ separators.add(path[0]); |
+ start = 1; |
+ } else { |
+ separators.add(''); |
+ } |
+ |
+ for (var i = start; i < path.length; i++) { |
+ if (style.isSeparator(path.codeUnitAt(i))) { |
+ parts.add(path.substring(start, i)); |
+ separators.add(path[i]); |
+ start = i + 1; |
+ } |
+ } |
+ |
+ // Add the final part, if any. |
+ if (start < path.length) { |
+ parts.add(path.substring(start)); |
+ separators.add(''); |
+ } |
+ |
+ return new ParsedPath._(style, root, isRootRelative, parts, separators); |
+ } |
+ |
+ ParsedPath._( |
+ this.style, this.root, this.isRootRelative, this.parts, this.separators); |
+ |
+ String get basename { |
+ var copy = this.clone(); |
+ copy.removeTrailingSeparators(); |
+ if (copy.parts.isEmpty) return root == null ? '' : root; |
+ return copy.parts.last; |
+ } |
+ |
+ String get basenameWithoutExtension => _splitExtension()[0]; |
+ |
+ bool get hasTrailingSeparator => |
+ !parts.isEmpty && (parts.last == '' || separators.last != ''); |
+ |
+ void removeTrailingSeparators() { |
+ while (!parts.isEmpty && parts.last == '') { |
+ parts.removeLast(); |
+ separators.removeLast(); |
+ } |
+ if (separators.length > 0) separators[separators.length - 1] = ''; |
+ } |
+ |
+ void normalize() { |
+ // Handle '.', '..', and empty parts. |
+ var leadingDoubles = 0; |
+ var newParts = <String>[]; |
+ for (var part in parts) { |
+ if (part == '.' || part == '') { |
+ // Do nothing. Ignore it. |
+ } else if (part == '..') { |
+ // Pop the last part off. |
+ if (newParts.length > 0) { |
+ newParts.removeLast(); |
+ } else { |
+ // Backed out past the beginning, so preserve the "..". |
+ leadingDoubles++; |
+ } |
+ } else { |
+ newParts.add(part); |
+ } |
+ } |
+ |
+ // A relative path can back out from the start directory. |
+ if (!isAbsolute) { |
+ newParts.insertAll(0, new List.filled(leadingDoubles, '..')); |
+ } |
+ |
+ // If we collapsed down to nothing, do ".". |
+ if (newParts.length == 0 && !isAbsolute) { |
+ newParts.add('.'); |
+ } |
+ |
+ // Canonicalize separators. |
+ var newSeparators = new List<String>.generate( |
+ newParts.length, (_) => style.separator, growable: true); |
+ newSeparators.insert(0, isAbsolute && |
+ newParts.length > 0 && |
+ style.needsSeparator(root) ? style.separator : ''); |
+ |
+ parts = newParts; |
+ separators = newSeparators; |
+ |
+ // Normalize the Windows root if needed. |
+ if (root != null && style == Style.windows) { |
+ root = root.replaceAll('/', '\\'); |
+ } |
+ removeTrailingSeparators(); |
+ } |
+ |
+ String toString() { |
+ var builder = new StringBuffer(); |
+ if (root != null) builder.write(root); |
+ for (var i = 0; i < parts.length; i++) { |
+ builder.write(separators[i]); |
+ builder.write(parts[i]); |
+ } |
+ builder.write(separators.last); |
+ |
+ return builder.toString(); |
+ } |
+ |
+ /// Splits the last non-empty part of the path into a `[basename, extension`] |
+ /// pair. |
+ /// |
+ /// Returns a two-element list. The first is the name of the file without any |
+ /// extension. The second is the extension or "" if it has none. |
+ List<String> _splitExtension() { |
+ var file = parts.lastWhere((p) => p != '', orElse: () => null); |
+ |
+ if (file == null) return ['', '']; |
+ if (file == '..') return ['..', '']; |
+ |
+ var lastDot = file.lastIndexOf('.'); |
+ |
+ // If there is no dot, or it's the first character, like '.bashrc', it |
+ // doesn't count. |
+ if (lastDot <= 0) return [file, '']; |
+ |
+ return [file.substring(0, lastDot), file.substring(lastDot)]; |
+ } |
+ |
+ ParsedPath clone() => new ParsedPath._(style, root, isRootRelative, |
+ new List.from(parts), new List.from(separators)); |
+} |