| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library glob.list_tree; | 5 library glob.list_tree; |
| 6 | 6 |
| 7 import 'dart:io'; | 7 import 'dart:io'; |
| 8 import 'dart:async'; | 8 import 'dart:async'; |
| 9 | 9 |
| 10 import 'package:path/path.dart' as p; | 10 import 'package:path/path.dart' as p; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 227 /// | 227 /// |
| 228 /// This determines which entities will ultimately be emitted when [list] is | 228 /// This determines which entities will ultimately be emitted when [list] is |
| 229 /// called. | 229 /// called. |
| 230 OptionsNode _validator; | 230 OptionsNode _validator; |
| 231 | 231 |
| 232 /// Whether this node is recursive. | 232 /// Whether this node is recursive. |
| 233 /// | 233 /// |
| 234 /// A recursive node has no children and is listed recursively. | 234 /// A recursive node has no children and is listed recursively. |
| 235 bool get isRecursive => children == null; | 235 bool get isRecursive => children == null; |
| 236 | 236 |
| 237 bool get _caseSensitive { |
| 238 if (_validator != null) return _validator.caseSensitive; |
| 239 if (children == null) return true; |
| 240 if (children.isEmpty) return true; |
| 241 return children.keys.first.caseSensitive; |
| 242 } |
| 243 |
| 237 /// Whether this node doesn't itself need to be listed. | 244 /// Whether this node doesn't itself need to be listed. |
| 238 /// | 245 /// |
| 239 /// If a node has no validator and all of its children are literal filenames, | 246 /// If a node has no validator and all of its children are literal filenames, |
| 240 /// there's no need to list its contents. We can just directly traverse into | 247 /// there's no need to list its contents. We can just directly traverse into |
| 241 /// its children. | 248 /// its children. |
| 242 bool get _isIntermediate { | 249 bool get _isIntermediate { |
| 243 if (_validator != null) return false; | 250 if (_validator != null) return false; |
| 251 if (!_caseSensitive) return false; |
| 244 return children.keys.every((sequence) => | 252 return children.keys.every((sequence) => |
| 245 sequence.nodes.length == 1 && sequence.nodes.first is LiteralNode); | 253 sequence.nodes.length == 1 && sequence.nodes.first is LiteralNode); |
| 246 } | 254 } |
| 247 | 255 |
| 248 /// Returns whether listing this node might return overlapping results. | 256 /// Returns whether listing this node might return overlapping results. |
| 249 bool get canOverlap { | 257 bool get canOverlap { |
| 250 // A recusive node can never overlap with itself, because it will only ever | 258 // A recusive node can never overlap with itself, because it will only ever |
| 251 // involve a single call to [Directory.list] that's then filtered with | 259 // involve a single call to [Directory.list] that's then filtered with |
| 252 // [_validator]. | 260 // [_validator]. |
| 253 if (isRecursive) return false; | 261 if (isRecursive) return false; |
| 254 | 262 |
| 255 // If there's more than one child node and at least one of the children is | 263 // If there's more than one child node and at least one of the children is |
| 256 // dynamic (that is, matches more than just a literal string), there may be | 264 // dynamic (that is, matches more than just a literal string), there may be |
| 257 // overlap. | 265 // overlap. |
| 258 if (children.length > 1 && children.keys.any((sequence) => | 266 if (children.length > 1) { |
| 267 // Case-insensitivity means that even literals may match multiple entries. |
| 268 if (!_caseSensitive) return true; |
| 269 |
| 270 if (children.keys.any((sequence) => |
| 259 sequence.nodes.length > 1 || sequence.nodes.single is! LiteralNode)) { | 271 sequence.nodes.length > 1 || sequence.nodes.single is! LiteralNode)) { |
| 260 return true; | 272 return true; |
| 273 } |
| 261 } | 274 } |
| 262 | 275 |
| 263 return children.values.any((node) => node.canOverlap); | 276 return children.values.any((node) => node.canOverlap); |
| 264 } | 277 } |
| 265 | 278 |
| 266 /// Creates a node with no children and no validator. | 279 /// Creates a node with no children and no validator. |
| 267 _ListTreeNode() | 280 _ListTreeNode() |
| 268 : children = new Map<SequenceNode, _ListTreeNode>(), | 281 : children = new Map<SequenceNode, _ListTreeNode>(), |
| 269 _validator = null; | 282 _validator = null; |
| 270 | 283 |
| 271 /// Creates a recursive node the given [validator]. | 284 /// Creates a recursive node the given [validator]. |
| 272 _ListTreeNode.recursive(SequenceNode validator) | 285 _ListTreeNode.recursive(SequenceNode validator) |
| 273 : children = null, | 286 : children = null, |
| 274 _validator = new OptionsNode([validator]); | 287 _validator = new OptionsNode([validator], |
| 288 caseSensitive: validator.caseSensitive); |
| 275 | 289 |
| 276 /// Transforms this into recursive node, folding all its children into its | 290 /// Transforms this into recursive node, folding all its children into its |
| 277 /// validator. | 291 /// validator. |
| 278 void makeRecursive() { | 292 void makeRecursive() { |
| 279 if (isRecursive) return; | 293 if (isRecursive) return; |
| 280 _validator = new OptionsNode(children.keys.map((sequence) { | 294 _validator = new OptionsNode(children.keys.map((sequence) { |
| 281 var child = children[sequence]; | 295 var child = children[sequence]; |
| 282 child.makeRecursive(); | 296 child.makeRecursive(); |
| 283 return _join([sequence, child._validator]); | 297 return _join([sequence, child._validator]); |
| 284 })); | 298 }), caseSensitive: _caseSensitive); |
| 285 children = null; | 299 children = null; |
| 286 } | 300 } |
| 287 | 301 |
| 288 /// Adds [validator] to this node's existing validator. | 302 /// Adds [validator] to this node's existing validator. |
| 289 void addOption(SequenceNode validator) { | 303 void addOption(SequenceNode validator) { |
| 290 if (_validator == null) { | 304 if (_validator == null) { |
| 291 _validator = new OptionsNode([validator]); | 305 _validator = new OptionsNode([validator], |
| 306 caseSensitive: validator.caseSensitive); |
| 292 } else { | 307 } else { |
| 293 _validator.options.add(validator); | 308 _validator.options.add(validator); |
| 294 } | 309 } |
| 295 } | 310 } |
| 296 | 311 |
| 297 /// Lists all entities within [dir] matching this node or its children. | 312 /// Lists all entities within [dir] matching this node or its children. |
| 298 /// | 313 /// |
| 299 /// This may return duplicate entities. These will be filtered out in | 314 /// This may return duplicate entities. These will be filtered out in |
| 300 /// [ListTree.list]. | 315 /// [ListTree.list]. |
| 301 Stream<FileSystemEntity> list(String dir, {bool followLinks: true}) { | 316 Stream<FileSystemEntity> list(String dir, {bool followLinks: true}) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 404 return _validator.matches(toPosixPath(p.context, path)); | 419 return _validator.matches(toPosixPath(p.context, path)); |
| 405 } | 420 } |
| 406 | 421 |
| 407 String toString() => "($_validator) $children"; | 422 String toString() => "($_validator) $children"; |
| 408 } | 423 } |
| 409 | 424 |
| 410 /// Joins each [components] into a new glob where each component is separated by | 425 /// Joins each [components] into a new glob where each component is separated by |
| 411 /// a path separator. | 426 /// a path separator. |
| 412 SequenceNode _join(Iterable<AstNode> components) { | 427 SequenceNode _join(Iterable<AstNode> components) { |
| 413 var componentsList = components.toList(); | 428 var componentsList = components.toList(); |
| 414 var nodes = [componentsList.removeAt(0)]; | 429 var first = componentsList.removeAt(0); |
| 430 var nodes = [first]; |
| 415 for (var component in componentsList) { | 431 for (var component in componentsList) { |
| 416 nodes.add(new LiteralNode('/')); | 432 nodes.add(new LiteralNode('/', caseSensitive: first.caseSensitive)); |
| 417 nodes.add(component); | 433 nodes.add(component); |
| 418 } | 434 } |
| 419 return new SequenceNode(nodes); | 435 return new SequenceNode(nodes, caseSensitive: first.caseSensitive); |
| 420 } | 436 } |
| OLD | NEW |