static List listFiles()

in lib/src/ignore.dart [220:300]


  static List<String> listFiles({
    String beneath = '',
    required Iterable<String> Function(String) listDir,
    required Ignore? Function(String) ignoreForDir,
    required bool Function(String) isDir,
    bool includeDirs = false,
  }) {
    if (beneath.startsWith('/') ||
        beneath.startsWith('./') ||
        beneath.startsWith('../')) {
      throw ArgumentError.value(
          'must be relative and normalized', 'beneath', beneath);
    }
    if (beneath.endsWith('/')) {
      throw ArgumentError.value('must not end with /', beneath);
    }
    // To streamline the algorithm we represent all paths as starting with '/'
    // and the empty path as just '/'.
    if (beneath == '.') beneath = '';
    beneath = '/$beneath';

    // Will contain all the files that are not ignored.
    final result = <String>[];
    // At any given point in the search, this will contain the Ignores from
    // directories leading up to the current entity.
    // The single `null` aligns popping and pushing in this stack with [toVisit]
    // below.
    final ignoreStack = <_IgnorePrefixPair?>[null];
    // Find all ignores between './' and [beneath] (not inclusive).

    // [index] points at the next '/' in the path.
    var index = -1;
    while ((index = beneath.indexOf('/', index + 1)) != -1) {
      final partial = beneath.substring(0, index + 1);
      if (_matchesStack(ignoreStack, partial)) {
        // A directory on the way towards [beneath] was ignored. Empty result.
        return <String>[];
      }
      final ignore = ignoreForDir(
          partial == '/' ? '.' : partial.substring(1, partial.length - 1));
      ignoreStack
          .add(ignore == null ? null : _IgnorePrefixPair(ignore, partial));
    }
    // Do a depth first tree-search starting at [beneath].
    // toVisit is a stack containing all items that are waiting to be processed.
    final toVisit = [
      [beneath]
    ];
    while (toVisit.isNotEmpty) {
      final topOfStack = toVisit.last;
      if (topOfStack.isEmpty) {
        toVisit.removeLast();
        ignoreStack.removeLast();
        continue;
      }
      final current = topOfStack.removeLast();
      // This is the version of current we present to the callbacks and in
      // [result].
      //
      // The empty path is represented as '.' and there is no leading '/'.
      final normalizedCurrent = current == '/' ? '.' : current.substring(1);
      final currentIsDir = isDir(normalizedCurrent);
      if (_matchesStack(ignoreStack, currentIsDir ? '$current/' : current)) {
        // current was ignored. Continue with the next item.
        continue;
      }
      if (currentIsDir) {
        final ignore = ignoreForDir(normalizedCurrent);
        ignoreStack
            .add(ignore == null ? null : _IgnorePrefixPair(ignore, current));
        // Put all entities in current on the stack to be processed.
        toVisit.add(listDir(normalizedCurrent).map((x) => '/$x').toList());
        if (includeDirs) {
          result.add(normalizedCurrent);
        }
      } else {
        result.add(normalizedCurrent);
      }
    }
    return result;
  }