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 |