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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library path.parsed_path;
6
7 import 'style.dart';
8
9 // TODO(rnystrom): Make this public?
10 class ParsedPath {
11 /// The [Style] that was used to parse this path.
12 Style style;
13
14 /// The absolute root portion of the path, or `null` if the path is relative.
15 /// On POSIX systems, this will be `null` or "/". On Windows, it can be
16 /// `null`, "//" for a UNC path, or something like "C:\" for paths with drive
17 /// letters.
18 String root;
19
20 /// Whether this path is root-relative.
21 ///
22 /// See [Context.isRootRelative].
23 bool isRootRelative;
24
25 /// The path-separated parts of the path. All but the last will be
26 /// directories.
27 List<String> parts;
28
29 /// The path separators preceding each part.
30 ///
31 /// The first one will be an empty string unless the root requires a separator
32 /// between it and the path. The last one will be an empty string unless the
33 /// path ends with a trailing separator.
34 List<String> separators;
35
36 /// The file extension of the last non-empty part, or "" if it doesn't have
37 /// one.
38 String get extension => _splitExtension()[1];
39
40 /// `true` if this is an absolute path.
41 bool get isAbsolute => root != null;
42
43 factory ParsedPath.parse(String path, Style style) {
44 var before = path;
45
46 // Remove the root prefix, if any.
47 var root = style.getRoot(path);
48 var isRootRelative = style.getRelativeRoot(path) != null;
49 if (root != null) path = path.substring(root.length);
50
51 // Split the parts on path separators.
52 var parts = [];
53 var separators = [];
54
55 var firstSeparator = style.separatorPattern.matchAsPrefix(path);
56 if (firstSeparator != null) {
57 separators.add(firstSeparator[0]);
58 path = path.substring(firstSeparator[0].length);
59 } else {
60 separators.add('');
61 }
62
63 var start = 0;
64 for (var match in style.separatorPattern.allMatches(path)) {
65 parts.add(path.substring(start, match.start));
66 separators.add(match[0]);
67 start = match.end;
68 }
69
70 // Add the final part, if any.
71 if (start < path.length) {
72 parts.add(path.substring(start));
73 separators.add('');
74 }
75
76 return new ParsedPath._(style, root, isRootRelative, parts, separators);
77 }
78
79 ParsedPath._(this.style, this.root, this.isRootRelative, this.parts,
80 this.separators);
81
82 String get basename {
83 var copy = this.clone();
84 copy.removeTrailingSeparators();
85 if (copy.parts.isEmpty) return root == null ? '' : root;
86 return copy.parts.last;
87 }
88
89 String get basenameWithoutExtension => _splitExtension()[0];
90
91 bool get hasTrailingSeparator =>
92 !parts.isEmpty && (parts.last == '' || separators.last != '');
93
94 void removeTrailingSeparators() {
95 while (!parts.isEmpty && parts.last == '') {
96 parts.removeLast();
97 separators.removeLast();
98 }
99 if (separators.length > 0) separators[separators.length - 1] = '';
100 }
101
102 void normalize() {
103 // Handle '.', '..', and empty parts.
104 var leadingDoubles = 0;
105 var newParts = [];
106 for (var part in parts) {
107 if (part == '.' || part == '') {
108 // Do nothing. Ignore it.
109 } else if (part == '..') {
110 // Pop the last part off.
111 if (newParts.length > 0) {
112 newParts.removeLast();
113 } else {
114 // Backed out past the beginning, so preserve the "..".
115 leadingDoubles++;
116 }
117 } else {
118 newParts.add(part);
119 }
120 }
121
122 // A relative path can back out from the start directory.
123 if (!isAbsolute) {
124 newParts.insertAll(0, new List.filled(leadingDoubles, '..'));
125 }
126
127 // If we collapsed down to nothing, do ".".
128 if (newParts.length == 0 && !isAbsolute) {
129 newParts.add('.');
130 }
131
132 // Canonicalize separators.
133 var newSeparators = new List.generate(
134 newParts.length, (_) => style.separator, growable: true);
135 newSeparators.insert(0,
136 isAbsolute && newParts.length > 0 &&
137 root.contains(style.needsSeparatorPattern) ?
138 style.separator : '');
139
140 parts = newParts;
141 separators = newSeparators;
142
143 // Normalize the Windows root if needed.
144 if (root != null && style == Style.windows) {
145 root = root.replaceAll('/', '\\');
146 }
147 removeTrailingSeparators();
148 }
149
150 String toString() {
151 var builder = new StringBuffer();
152 if (root != null) builder.write(root);
153 for (var i = 0; i < parts.length; i++) {
154 builder.write(separators[i]);
155 builder.write(parts[i]);
156 }
157 builder.write(separators.last);
158
159 return builder.toString();
160 }
161
162 /// Splits the last non-empty part of the path into a `[basename, extension`]
163 /// pair.
164 ///
165 /// Returns a two-element list. The first is the name of the file without any
166 /// extension. The second is the extension or "" if it has none.
167 List<String> _splitExtension() {
168 var file = parts.lastWhere((p) => p != '', orElse: () => null);
169
170 if (file == null) return ['', ''];
171 if (file == '..') return ['..', ''];
172
173 var lastDot = file.lastIndexOf('.');
174
175 // If there is no dot, or it's the first character, like '.bashrc', it
176 // doesn't count.
177 if (lastDot <= 0) return [file, ''];
178
179 return [file.substring(0, lastDot), file.substring(lastDot)];
180 }
181
182 ParsedPath clone() => new ParsedPath._(
183 style, root, isRootRelative,
184 new List.from(parts), new List.from(separators));
185 }
186
OLDNEW
« 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