| OLD | NEW | 
|---|
|  | (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 'internal_style.dart'; |  | 
| 8 import 'style.dart'; |  | 
| 9 |  | 
| 10 class ParsedPath { |  | 
| 11   /// The [InternalStyle] that was used to parse this path. |  | 
| 12   InternalStyle 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, InternalStyle style) { |  | 
| 44     // Remove the root prefix, if any. |  | 
| 45     var root = style.getRoot(path); |  | 
| 46     var isRootRelative = style.isRootRelative(path); |  | 
| 47     if (root != null) path = path.substring(root.length); |  | 
| 48 |  | 
| 49     // Split the parts on path separators. |  | 
| 50     var parts = <String>[]; |  | 
| 51     var separators = <String>[]; |  | 
| 52 |  | 
| 53     var start = 0; |  | 
| 54 |  | 
| 55     if (path.isNotEmpty && style.isSeparator(path.codeUnitAt(0))) { |  | 
| 56       separators.add(path[0]); |  | 
| 57       start = 1; |  | 
| 58     } else { |  | 
| 59       separators.add(''); |  | 
| 60     } |  | 
| 61 |  | 
| 62     for (var i = start; i < path.length; i++) { |  | 
| 63       if (style.isSeparator(path.codeUnitAt(i))) { |  | 
| 64         parts.add(path.substring(start, i)); |  | 
| 65         separators.add(path[i]); |  | 
| 66         start = i + 1; |  | 
| 67       } |  | 
| 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._( |  | 
| 80       this.style, this.root, this.isRootRelative, this.parts, 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 = <String>[]; |  | 
| 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<String>.generate( |  | 
| 134         newParts.length, (_) => style.separator, growable: true); |  | 
| 135     newSeparators.insert(0, isAbsolute && |  | 
| 136         newParts.length > 0 && |  | 
| 137         style.needsSeparator(root) ? style.separator : ''); |  | 
| 138 |  | 
| 139     parts = newParts; |  | 
| 140     separators = newSeparators; |  | 
| 141 |  | 
| 142     // Normalize the Windows root if needed. |  | 
| 143     if (root != null && style == Style.windows) { |  | 
| 144       root = root.replaceAll('/', '\\'); |  | 
| 145     } |  | 
| 146     removeTrailingSeparators(); |  | 
| 147   } |  | 
| 148 |  | 
| 149   String toString() { |  | 
| 150     var builder = new StringBuffer(); |  | 
| 151     if (root != null) builder.write(root); |  | 
| 152     for (var i = 0; i < parts.length; i++) { |  | 
| 153       builder.write(separators[i]); |  | 
| 154       builder.write(parts[i]); |  | 
| 155     } |  | 
| 156     builder.write(separators.last); |  | 
| 157 |  | 
| 158     return builder.toString(); |  | 
| 159   } |  | 
| 160 |  | 
| 161   /// Splits the last non-empty part of the path into a `[basename, extension`] |  | 
| 162   /// pair. |  | 
| 163   /// |  | 
| 164   /// Returns a two-element list. The first is the name of the file without any |  | 
| 165   /// extension. The second is the extension or "" if it has none. |  | 
| 166   List<String> _splitExtension() { |  | 
| 167     var file = parts.lastWhere((p) => p != '', orElse: () => null); |  | 
| 168 |  | 
| 169     if (file == null) return ['', '']; |  | 
| 170     if (file == '..') return ['..', '']; |  | 
| 171 |  | 
| 172     var lastDot = file.lastIndexOf('.'); |  | 
| 173 |  | 
| 174     // If there is no dot, or it's the first character, like '.bashrc', it |  | 
| 175     // doesn't count. |  | 
| 176     if (lastDot <= 0) return [file, '']; |  | 
| 177 |  | 
| 178     return [file.substring(0, lastDot), file.substring(lastDot)]; |  | 
| 179   } |  | 
| 180 |  | 
| 181   ParsedPath clone() => new ParsedPath._(style, root, isRootRelative, |  | 
| 182       new List.from(parts), new List.from(separators)); |  | 
| 183 } |  | 
| OLD | NEW | 
|---|