Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Unified Diff: pkg/path/lib/src/parsed_path.dart

Issue 62753005: Refactor pkg/path. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: code review Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/path/lib/src/context.dart ('k') | pkg/path/lib/src/path_exception.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/path/lib/src/parsed_path.dart
diff --git a/pkg/path/lib/src/parsed_path.dart b/pkg/path/lib/src/parsed_path.dart
new file mode 100644
index 0000000000000000000000000000000000000000..5356b44c1df809acbebf45a7bddb273d79870458
--- /dev/null
+++ b/pkg/path/lib/src/parsed_path.dart
@@ -0,0 +1,186 @@
+// 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 'style.dart';
+
+// TODO(rnystrom): Make this public?
+class ParsedPath {
+ /// The [Style] that was used to parse this path.
+ Style 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, Style style) {
+ var before = path;
+
+ // Remove the root prefix, if any.
+ var root = style.getRoot(path);
+ var isRootRelative = style.getRelativeRoot(path) != null;
+ if (root != null) path = path.substring(root.length);
+
+ // Split the parts on path separators.
+ var parts = [];
+ var separators = [];
+
+ var firstSeparator = style.separatorPattern.matchAsPrefix(path);
+ if (firstSeparator != null) {
+ separators.add(firstSeparator[0]);
+ path = path.substring(firstSeparator[0].length);
+ } else {
+ separators.add('');
+ }
+
+ var start = 0;
+ for (var match in style.separatorPattern.allMatches(path)) {
+ parts.add(path.substring(start, match.start));
+ separators.add(match[0]);
+ start = match.end;
+ }
+
+ // 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 = [];
+ 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.generate(
+ newParts.length, (_) => style.separator, growable: true);
+ newSeparators.insert(0,
+ isAbsolute && newParts.length > 0 &&
+ root.contains(style.needsSeparatorPattern) ?
+ 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));
+}
+
« no previous file with comments | « pkg/path/lib/src/context.dart ('k') | pkg/path/lib/src/path_exception.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698